Showing preview only (1,683K chars total). Download the full file or copy to clipboard to get everything.
Repository: nhn/tui.calendar
Branch: main
Commit: b53e765e8d89
Files: 455
Total size: 1.5 MB
Directory structure:
gitextract_fijh9az9/
├── .eslintignore
├── .eslintrc.js
├── .github/
│ ├── composite-actions/
│ │ └── install-dependencies/
│ │ └── action.yml
│ └── workflows/
│ ├── publish-calendar.yml
│ ├── publish-docs.yml
│ ├── publish-wrappers.yml
│ └── test.yml
├── .gitignore
├── .husky/
│ ├── .gitignore
│ └── pre-commit
├── .prettierignore
├── .prettierrc
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── apps/
│ ├── calendar/
│ │ ├── .browserslistrc
│ │ ├── .lintstagedrc.js
│ │ ├── .storybook/
│ │ │ ├── main.js
│ │ │ ├── manager.js
│ │ │ ├── preview.js
│ │ │ └── theme.js
│ │ ├── README.md
│ │ ├── examples/
│ │ │ ├── 00-calendar-app.html
│ │ │ ├── 01-monthly-view-basic.html
│ │ │ ├── 02-monthly-view-2weeks.html
│ │ │ ├── 03-monthly-view-3weeks.html
│ │ │ ├── 04-weekly-view.html
│ │ │ ├── 05-weekly-view-no-event-view.html
│ │ │ ├── 06-daily-view.html
│ │ │ ├── 07-narrow-weekends.html
│ │ │ ├── 08-hidden-weekends.html
│ │ │ ├── 09-timezone.html
│ │ │ ├── 10-theme-common.html
│ │ │ ├── 11-theme-monthly.html
│ │ │ ├── 12-theme-weekly.html
│ │ │ ├── 13-template-monthly.html
│ │ │ ├── 14-template-weekly.html
│ │ │ ├── 15-template-popup.html
│ │ │ ├── scripts/
│ │ │ │ ├── app.js
│ │ │ │ ├── mock-data.js
│ │ │ │ └── utils.js
│ │ │ └── styles/
│ │ │ ├── app.css
│ │ │ ├── icons.css
│ │ │ └── reset.css
│ │ ├── jest.config.js
│ │ ├── jsdoc.conf.json
│ │ ├── package.json
│ │ ├── playwright/
│ │ │ ├── assertions.ts
│ │ │ ├── configs.ts
│ │ │ ├── constants.ts
│ │ │ ├── day/
│ │ │ │ ├── timeGridEventMoving.e2e.ts
│ │ │ │ ├── timeGridEventResizing.e2e.ts
│ │ │ │ ├── timeGridScrollSync.e2e.ts
│ │ │ │ └── timeGridSelection.e2e.ts
│ │ │ ├── month/
│ │ │ │ ├── accumulatedGridSelection.e2e.ts
│ │ │ │ ├── eventMoving.e2e.ts
│ │ │ │ ├── eventResizing.e2e.ts
│ │ │ │ ├── gridSelection.e2e.ts
│ │ │ │ ├── seeMoreEventsPopup.e2e.ts
│ │ │ │ └── visibleEventCount.e2e.ts
│ │ │ ├── playwright-env.d.ts
│ │ │ ├── types.ts
│ │ │ ├── utils.ts
│ │ │ └── week/
│ │ │ ├── alldayGridEventMoving.e2e.ts
│ │ │ ├── alldayGridEventResizing.e2e.ts
│ │ │ ├── dayGridSelection.e2e.ts
│ │ │ ├── hourStartOption.e2e.ts
│ │ │ ├── primaryTimezone.e2e.ts
│ │ │ ├── timeGridEventClick.e2e.ts
│ │ │ ├── timeGridEventMoving.e2e.ts
│ │ │ ├── timeGridEventResizing.e2e.ts
│ │ │ ├── timeGridScrollSync.e2e.ts
│ │ │ └── timeGridSelection.e2e.ts
│ │ ├── postcss.config.js
│ │ ├── scripts/
│ │ │ ├── publishToCDN.js
│ │ │ └── updateWrapper.js
│ │ ├── src/
│ │ │ ├── calendarContainer.tsx
│ │ │ ├── components/
│ │ │ │ ├── dayGridCommon/
│ │ │ │ │ ├── dayName.tsx
│ │ │ │ │ ├── gridHeader.tsx
│ │ │ │ │ └── gridSelection.tsx
│ │ │ │ ├── dayGridMonth/
│ │ │ │ │ ├── accumulatedGridSelection.tsx
│ │ │ │ │ ├── cellHeader.tsx
│ │ │ │ │ ├── dayGridMonth.tsx
│ │ │ │ │ ├── gridCell.tsx
│ │ │ │ │ ├── gridRow.tsx
│ │ │ │ │ ├── gridSelectionByRow.tsx
│ │ │ │ │ ├── monthEvents.tsx
│ │ │ │ │ ├── moreEventsButton.tsx
│ │ │ │ │ ├── movingEventShadow.tsx
│ │ │ │ │ └── resizingGuideByRow.tsx
│ │ │ │ ├── dayGridWeek/
│ │ │ │ │ ├── alldayGridRow.tsx
│ │ │ │ │ ├── alldayGridSelection.tsx
│ │ │ │ │ ├── gridCell.tsx
│ │ │ │ │ ├── gridCells.tsx
│ │ │ │ │ ├── movingEventShadow.tsx
│ │ │ │ │ ├── otherGridRow.tsx
│ │ │ │ │ └── resizingEventShadow.tsx
│ │ │ │ ├── events/
│ │ │ │ │ ├── backgroundEvent.tsx
│ │ │ │ │ ├── horizontalEvent.spec.tsx
│ │ │ │ │ ├── horizontalEvent.tsx
│ │ │ │ │ ├── horizontalEventResizeIcon.tsx
│ │ │ │ │ ├── timeEvent.spec.tsx
│ │ │ │ │ └── timeEvent.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── panel.tsx
│ │ │ │ ├── panelResizer.tsx
│ │ │ │ ├── popup/
│ │ │ │ │ ├── calendarDropdownMenu.tsx
│ │ │ │ │ ├── calendarSelector.tsx
│ │ │ │ │ ├── closePopupButton.tsx
│ │ │ │ │ ├── confirmPopupButton.tsx
│ │ │ │ │ ├── dateSelector.tsx
│ │ │ │ │ ├── eventDetailPopup.spec.tsx
│ │ │ │ │ ├── eventDetailPopup.tsx
│ │ │ │ │ ├── eventDetailSectionDetail.tsx
│ │ │ │ │ ├── eventDetailSectionHeader.tsx
│ │ │ │ │ ├── eventFormPopup.spec.tsx
│ │ │ │ │ ├── eventFormPopup.tsx
│ │ │ │ │ ├── eventStateSelector.tsx
│ │ │ │ │ ├── locationInputBox.tsx
│ │ │ │ │ ├── popupOverlay.tsx
│ │ │ │ │ ├── popupSection.tsx
│ │ │ │ │ ├── seeMoreEventsPopup.tsx
│ │ │ │ │ ├── stateDropdownMenu.tsx
│ │ │ │ │ └── titleInputBox.tsx
│ │ │ │ ├── template.tsx
│ │ │ │ ├── timeGrid/
│ │ │ │ │ ├── column.tsx
│ │ │ │ │ ├── gridLines.tsx
│ │ │ │ │ ├── gridSelectionByColumn.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── movingEventShadow.tsx
│ │ │ │ │ ├── nowIndicator.tsx
│ │ │ │ │ ├── nowIndicatorLabel.tsx
│ │ │ │ │ ├── resizingGuideByColumn.tsx
│ │ │ │ │ ├── timeColumn.tsx
│ │ │ │ │ ├── timeGrid.spec.tsx
│ │ │ │ │ ├── timeGrid.tsx
│ │ │ │ │ ├── timezoneCollapseButton.tsx
│ │ │ │ │ ├── timezoneCollpaseButton.spec.tsx
│ │ │ │ │ └── timezoneLabels.tsx
│ │ │ │ └── view/
│ │ │ │ ├── day.spec.tsx
│ │ │ │ ├── day.tsx
│ │ │ │ ├── main.tsx
│ │ │ │ ├── month.spec.tsx
│ │ │ │ ├── month.tsx
│ │ │ │ ├── week.spec.tsx
│ │ │ │ └── week.tsx
│ │ │ ├── constants/
│ │ │ │ ├── error.ts
│ │ │ │ ├── grid.ts
│ │ │ │ ├── keyboard.ts
│ │ │ │ ├── layout.ts
│ │ │ │ ├── message.ts
│ │ │ │ ├── mouse.ts
│ │ │ │ ├── popup.ts
│ │ │ │ ├── statistics.ts
│ │ │ │ ├── style.ts
│ │ │ │ ├── theme.ts
│ │ │ │ └── view.ts
│ │ │ ├── contexts/
│ │ │ │ ├── calendarStore.ts
│ │ │ │ ├── eventBus.spec.tsx
│ │ │ │ ├── eventBus.tsx
│ │ │ │ ├── floatingLayer.tsx
│ │ │ │ ├── layoutContainer.tsx
│ │ │ │ └── themeStore.tsx
│ │ │ ├── controller/
│ │ │ │ ├── base.spec.ts
│ │ │ │ ├── base.ts
│ │ │ │ ├── column.spec.ts
│ │ │ │ ├── column.ts
│ │ │ │ ├── core.spec.ts
│ │ │ │ ├── core.ts
│ │ │ │ ├── month.spec.ts
│ │ │ │ ├── month.ts
│ │ │ │ ├── times.spec.ts
│ │ │ │ ├── times.ts
│ │ │ │ ├── week.spec.ts
│ │ │ │ └── week.ts
│ │ │ ├── css/
│ │ │ │ ├── common.css
│ │ │ │ ├── daygrid/
│ │ │ │ │ ├── dayGrid.css
│ │ │ │ │ ├── dayNames.css
│ │ │ │ │ └── index.css
│ │ │ │ ├── events/
│ │ │ │ │ ├── background.css
│ │ │ │ │ ├── grid.css
│ │ │ │ │ ├── index.css
│ │ │ │ │ └── time.css
│ │ │ │ ├── icons.css
│ │ │ │ ├── index.css
│ │ │ │ ├── layout.css
│ │ │ │ ├── panel/
│ │ │ │ │ ├── allday.css
│ │ │ │ │ └── index.css
│ │ │ │ ├── popup/
│ │ │ │ │ ├── common.css
│ │ │ │ │ ├── detail.css
│ │ │ │ │ ├── form.css
│ │ │ │ │ ├── index.css
│ │ │ │ │ └── seeMore.css
│ │ │ │ └── timegrid/
│ │ │ │ ├── column.css
│ │ │ │ ├── index.css
│ │ │ │ ├── timeColumn.css
│ │ │ │ └── timegrid.css
│ │ │ ├── factory/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── calendarCore.spec.tsx.snap
│ │ │ │ ├── calendar.tsx
│ │ │ │ ├── calendarCore.spec.tsx
│ │ │ │ ├── calendarCore.tsx
│ │ │ │ ├── day.tsx
│ │ │ │ ├── month.spec.tsx
│ │ │ │ ├── month.tsx
│ │ │ │ ├── week.spec.tsx
│ │ │ │ └── week.tsx
│ │ │ ├── helpers/
│ │ │ │ ├── css.spec.ts
│ │ │ │ ├── css.ts
│ │ │ │ ├── dayName.ts
│ │ │ │ ├── drag.ts
│ │ │ │ ├── events.spec.ts
│ │ │ │ ├── events.ts
│ │ │ │ ├── grid.spec.ts
│ │ │ │ ├── grid.ts
│ │ │ │ ├── gridSelection.ts
│ │ │ │ ├── popup.ts
│ │ │ │ └── view.ts
│ │ │ ├── hooks/
│ │ │ │ ├── calendar/
│ │ │ │ │ ├── useCalendarById.ts
│ │ │ │ │ ├── useCalendarColor.ts
│ │ │ │ │ └── useCalendarData.ts
│ │ │ │ ├── common/
│ │ │ │ │ ├── useClickPrevention.spec.tsx
│ │ │ │ │ ├── useClickPrevention.ts
│ │ │ │ │ ├── useDOMNode.ts
│ │ │ │ │ ├── useDrag.spec.tsx
│ │ │ │ │ ├── useDrag.ts
│ │ │ │ │ ├── useDropdownState.ts
│ │ │ │ │ ├── useInterval.spec.ts
│ │ │ │ │ ├── useInterval.ts
│ │ │ │ │ ├── useIsMounted.spec.ts
│ │ │ │ │ ├── useIsMounted.ts
│ │ │ │ │ ├── useKeydownEvent.ts
│ │ │ │ │ ├── useTransientUpdate.ts
│ │ │ │ │ └── useWhen.ts
│ │ │ │ ├── dayGridMonth/
│ │ │ │ │ ├── useDayGridMonthEventMove.ts
│ │ │ │ │ └── useDayGridMonthEventResize.ts
│ │ │ │ ├── dayGridWeek/
│ │ │ │ │ ├── useAlldayGridRowEventMove.ts
│ │ │ │ │ ├── useAlldayGridRowEventResize.ts
│ │ │ │ │ └── useGridRowHeightController.ts
│ │ │ │ ├── event/
│ │ │ │ │ ├── useCurrentPointerPositionInGrid.ts
│ │ │ │ │ └── useDraggingEvent.ts
│ │ │ │ ├── gridSelection/
│ │ │ │ │ ├── useGridSelection.spec.tsx
│ │ │ │ │ └── useGridSelection.ts
│ │ │ │ ├── popup/
│ │ │ │ │ └── useFormState.ts
│ │ │ │ ├── template/
│ │ │ │ │ └── useStringOnlyTemplate.ts
│ │ │ │ ├── timeGrid/
│ │ │ │ │ ├── useTimeGridEventMove.spec.tsx
│ │ │ │ │ ├── useTimeGridEventMove.ts
│ │ │ │ │ ├── useTimeGridEventResize.ts
│ │ │ │ │ ├── useTimeGridScrollSync.ts
│ │ │ │ │ └── useTimezoneLabelsTop.ts
│ │ │ │ └── timezone/
│ │ │ │ ├── useEventsWithTimezone.ts
│ │ │ │ ├── usePrimaryTimezone.ts
│ │ │ │ ├── useTZConverter.spec.ts
│ │ │ │ └── useTZConverter.ts
│ │ │ ├── index.ts
│ │ │ ├── jest.d.ts
│ │ │ ├── model/
│ │ │ │ ├── eventModel.spec.ts
│ │ │ │ ├── eventModel.ts
│ │ │ │ └── eventUIModel.ts
│ │ │ ├── selectors/
│ │ │ │ ├── index.ts
│ │ │ │ ├── options.ts
│ │ │ │ ├── popup.ts
│ │ │ │ ├── theme.ts
│ │ │ │ └── timezone.ts
│ │ │ ├── setupTests.ts
│ │ │ ├── slices/
│ │ │ │ ├── calendar.ts
│ │ │ │ ├── dnd.ts
│ │ │ │ ├── gridSelection.ts
│ │ │ │ ├── layout.ts
│ │ │ │ ├── options.ts
│ │ │ │ ├── popup.ts
│ │ │ │ ├── template.ts
│ │ │ │ ├── view.spec.ts
│ │ │ │ └── view.ts
│ │ │ ├── store/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ ├── index.ts
│ │ │ │ └── internal.ts
│ │ │ ├── template/
│ │ │ │ ├── default.tsx
│ │ │ │ ├── index.ts
│ │ │ │ └── template.spec.tsx
│ │ │ ├── test/
│ │ │ │ ├── cssFileMock.ts
│ │ │ │ ├── helpers.ts
│ │ │ │ ├── matchers.ts
│ │ │ │ ├── testIds.ts
│ │ │ │ └── utils.tsx
│ │ │ ├── theme/
│ │ │ │ ├── common.ts
│ │ │ │ ├── dispatch.spec.tsx
│ │ │ │ ├── dispatch.ts
│ │ │ │ ├── month.ts
│ │ │ │ └── week.ts
│ │ │ ├── time/
│ │ │ │ ├── date.spec.ts
│ │ │ │ ├── date.ts
│ │ │ │ ├── datetime.spec.ts
│ │ │ │ ├── datetime.ts
│ │ │ │ ├── timezone.spec.ts
│ │ │ │ └── timezone.ts
│ │ │ ├── tui-code-snippet.d.ts
│ │ │ ├── types/
│ │ │ │ ├── components/
│ │ │ │ │ ├── common.ts
│ │ │ │ │ └── gridSelection.ts
│ │ │ │ ├── drag.ts
│ │ │ │ ├── eventBus.ts
│ │ │ │ ├── events.ts
│ │ │ │ ├── grid.ts
│ │ │ │ ├── mouse.ts
│ │ │ │ ├── options.ts
│ │ │ │ ├── panel.ts
│ │ │ │ ├── store.ts
│ │ │ │ ├── template.ts
│ │ │ │ ├── theme.ts
│ │ │ │ ├── time/
│ │ │ │ │ └── datetime.ts
│ │ │ │ └── util.ts
│ │ │ └── utils/
│ │ │ ├── array.spec.ts
│ │ │ ├── array.ts
│ │ │ ├── collection.spec.ts
│ │ │ ├── collection.ts
│ │ │ ├── dom.spec.ts
│ │ │ ├── dom.ts
│ │ │ ├── error.ts
│ │ │ ├── eventBus.ts
│ │ │ ├── keyboard.ts
│ │ │ ├── logger.ts
│ │ │ ├── math.spec.ts
│ │ │ ├── math.ts
│ │ │ ├── noop.ts
│ │ │ ├── object.spec.ts
│ │ │ ├── object.ts
│ │ │ ├── preact.ts
│ │ │ ├── requestTimeout.spec.ts
│ │ │ ├── requestTimeout.ts
│ │ │ ├── sanitizer.ts
│ │ │ ├── stamp.ts
│ │ │ ├── string.spec.ts
│ │ │ ├── string.ts
│ │ │ ├── type.spec.ts
│ │ │ └── type.ts
│ │ ├── stories/
│ │ │ ├── column.stories.tsx
│ │ │ ├── data/
│ │ │ │ └── events.json
│ │ │ ├── dayGridMonth.stories.tsx
│ │ │ ├── dayView.stories.tsx
│ │ │ ├── e2e/
│ │ │ │ ├── day.stories.tsx
│ │ │ │ ├── month.stories.tsx
│ │ │ │ └── week.stories.tsx
│ │ │ ├── eventDetailPopup.stories.tsx
│ │ │ ├── eventFormPopup.stories.tsx
│ │ │ ├── events.stories.tsx
│ │ │ ├── gridHeader.stories.tsx
│ │ │ ├── gridRow.stories.tsx
│ │ │ ├── helper/
│ │ │ │ └── event.ts
│ │ │ ├── layout.stories.tsx
│ │ │ ├── main.stories.tsx
│ │ │ ├── mocks/
│ │ │ │ ├── mockCalendars.ts
│ │ │ │ ├── mockDayViewEvents.ts
│ │ │ │ ├── mockMonthViewEvents.ts
│ │ │ │ ├── mockWeekViewEvents.ts
│ │ │ │ └── types.ts
│ │ │ ├── monthView.stories.tsx
│ │ │ ├── timegrid.stories.tsx
│ │ │ ├── util/
│ │ │ │ ├── calendarExample.tsx
│ │ │ │ ├── mockCalendarDates.ts
│ │ │ │ ├── mockCalendars.ts
│ │ │ │ ├── providerWrapper.tsx
│ │ │ │ └── randomEvents.ts
│ │ │ └── weekView.stories.tsx
│ │ ├── stylelint.config.js
│ │ ├── tsconfig.declaration.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.test.json
│ │ ├── tuidoc.config.json
│ │ ├── vite.config.ts
│ │ └── webpack.config.js
│ ├── react-calendar/
│ │ ├── .browserslistrc
│ │ ├── .eslintrc.js
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── docs/
│ │ │ ├── README.md
│ │ │ ├── en/
│ │ │ │ └── guide/
│ │ │ │ ├── getting-started.md
│ │ │ │ └── migration-guide-v2.md
│ │ │ └── ko/
│ │ │ ├── README.md
│ │ │ └── guide/
│ │ │ ├── getting-started.md
│ │ │ └── migration-guide-v2.md
│ │ ├── example/
│ │ │ ├── app.css
│ │ │ ├── app.tsx
│ │ │ ├── index.html
│ │ │ ├── main.tsx
│ │ │ ├── theme.ts
│ │ │ └── utils.ts
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.tsx
│ │ │ └── isEqual.ts
│ │ ├── tsconfig.declaration.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ └── vue-calendar/
│ ├── .eslintignore
│ ├── .eslintrc.js
│ ├── .lintstagedrc.js
│ ├── README.md
│ ├── docs/
│ │ ├── README.md
│ │ ├── en/
│ │ │ └── guide/
│ │ │ ├── getting-started.md
│ │ │ └── migration-guide-v2.md
│ │ └── ko/
│ │ ├── README.md
│ │ └── guide/
│ │ ├── getting-started.md
│ │ └── migration-guide-v2.md
│ ├── example/
│ │ ├── App.vue
│ │ ├── app.css
│ │ ├── index.html
│ │ ├── main.js
│ │ ├── mock-data.js
│ │ ├── theme.js
│ │ └── utils.js
│ ├── index.d.ts
│ ├── package.json
│ ├── src/
│ │ └── Calendar.js
│ └── vite.config.js
├── babel.config.json
├── docs/
│ ├── COMMIT_MESSAGE_CONVENTION.md
│ ├── ISSUE_TEMPLATE.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── README.md
│ ├── en/
│ │ ├── apis/
│ │ │ ├── calendar.md
│ │ │ ├── event-object.md
│ │ │ ├── options.md
│ │ │ ├── template.md
│ │ │ ├── theme.md
│ │ │ └── tzdate.md
│ │ └── guide/
│ │ ├── getting-started.md
│ │ └── migration-guide-v2.md
│ └── ko/
│ ├── README.md
│ ├── apis/
│ │ ├── calendar.md
│ │ ├── event-object.md
│ │ ├── options.md
│ │ ├── template.md
│ │ ├── theme.md
│ │ └── tzdate.md
│ └── guide/
│ ├── getting-started.md
│ └── migration-guide-v2.md
├── jest.config.js
├── libs/
│ └── date/
│ ├── .eslintrc.js
│ ├── index.d.ts
│ ├── jest.config.js
│ ├── package.json
│ ├── src/
│ │ ├── index.js
│ │ ├── localDate.js
│ │ ├── momentDate.js
│ │ └── utcDate.js
│ ├── test/
│ │ ├── localDate.spec.js
│ │ ├── momentDate.moment-timezone.spec.js
│ │ ├── momentDate.moment.spec.js
│ │ └── utcDate.spec.js
│ ├── tsBannerGenerator.js
│ ├── tuidoc.config.json
│ └── webpack.config.js
├── package.json
├── playwright.config.ts
└── scripts/
└── replaceLinkInReadme.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintignore
================================================
build/
dist/
node_modules/
perf/
================================================
FILE: .eslintrc.js
================================================
const defaultExtends = [
'tui',
'prettier',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:prettier/recommended',
];
module.exports = {
root: true,
env: {
browser: true,
es6: true,
node: true,
},
parser: '@typescript-eslint/parser',
parserOptions: {
parser: 'typescript-eslint-parser',
ecmaVersion: 2018,
sourceType: 'module',
},
plugins: [
'unused-imports',
'simple-import-sort',
'prettier',
'react',
'react-hooks',
'@typescript-eslint',
'jest',
],
extends: defaultExtends,
settings: {
react: {
pragma: 'h',
version: '16.13',
},
},
globals: {
fixture: true,
},
ignorePatterns: ['**/*.d.ts'],
rules: {
'@typescript-eslint/explicit-module-boundary-types': 0,
'@typescript-eslint/ban-types': 0,
'@typescript-eslint/no-use-before-define': 0,
'@typescript-eslint/explicit-function-return-type': 0,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-shadow': 'error',
'@typescript-eslint/consistent-type-imports': 'error',
'no-duplicate-imports': 'off',
'@typescript-eslint/no-duplicate-imports': 'error',
'no-shadow': 'off',
'no-use-before-define': 0,
// use unused-imports plugin
'@typescript-eslint/no-unused-vars': 'off',
'unused-imports/no-unused-imports': 'error',
'unused-imports/no-unused-vars': [
'warn',
{ args: 'after-used', argsIgnorePattern: '^_', ignoreRestSiblings: true },
],
'react/prop-types': 0,
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error',
'jest/no-conditional-expect': 0,
'simple-import-sort/imports': [
'warn',
{
groups: [
// Side effect imports.
['^\\u0000'],
// Preact.
['^preact'],
// Any other packages.
['^(\\w|@)(?!src/|test/|stories/|t/)'],
// Source files.
['^@src/'],
// stories files
['^@stories/'],
// Types.
['^@t/'],
// Absolute imports and other imports such as Vue-style `@/foo`.
// Anything not matched in another group.
['^'],
// Relative imports.
// Anything that starts with a dot.
['^\\.'],
],
},
],
'simple-import-sort/exports': 'warn',
complexity: ['error', { max: 8 }],
'no-warning-comments': 0,
},
overrides: [
{
files: ['*.spec.ts', '*.spec.tsx'],
extends: ['plugin:jest/recommended'],
rules: {
'max-nested-callbacks': ['error', { max: 5 }],
'jest/expect-expect': [
'warn',
{
assertFunctionNames: ['expect', 'assert*'],
},
],
'jest/no-conditional-expect': 'warn',
},
},
{
files: ['apps/calendar/playwright/**/*.ts'],
extends: ['plugin:playwright/playwright-test'],
rules: {
'playwright/no-force-option': 'off',
'max-nested-callbacks': ['error', { max: 5 }],
'dot-notation': ['error', { allowKeywords: true }],
},
},
],
};
================================================
FILE: .github/composite-actions/install-dependencies/action.yml
================================================
name: 'Install root dependencies using cache'
description: 'Set Node.js and install dependencies using cache'
runs:
using: 'composite'
steps:
- name: Setup timezone
uses: szenius/set-timezone@v1.0
with:
timezoneLinux: 'Asia/Seoul'
- name: Use Node.js 16
uses: actions/setup-node@v3
with:
node-version: '16'
registry-url: https://registry.npmjs.org/
cache: 'npm'
- name: Install dependencies
run: npm ci
shell: bash
================================================
FILE: .github/workflows/publish-calendar.yml
================================================
name: Publish calendar
on: [workflow_dispatch]
env:
WORKING_DIRECTORY: ./apps/calendar
jobs:
check-version:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v3
- name: Check the package version
id: cpv
uses: PostHog/check-package-version@v2
with:
path: ${{ env.WORKING_DIRECTORY }}
- name: Log when unchanged
if: steps.cpv.outputs.is-new-version == 'false'
run: 'echo "No version change"'
- name: Cancel workflow
if: steps.cpv.outputs.is-new-version == 'false'
uses: andymckay/cancel-action@0.2
publish-npm:
needs: check-version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install dependencies
uses: ./.github/composite-actions/install-dependencies
- name: Build calendar
run: |
npm run build:calendar
- name: Check package version
id: cpv
uses: PostHog/check-package-version@v2
with:
path: ${{ env.WORKING_DIRECTORY }}
- name: Create new version tag
run: |
git tag calendar@${{ steps.cpv.outputs.committed-version }}
- name: Push new version tag
run: |
git push origin calendar@${{ steps.cpv.outputs.committed-version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update the relative links in README
run: |
PACKAGES=core npm run update:readme
- name: Publish the package to npm (Calendar)
working-directory: ${{ env.WORKING_DIRECTORY }}
run: |
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-cdn:
needs: publish-npm
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v3
- uses: ./.github/composite-actions/install-dependencies
- name: Upload files to CDN
working-directory: ${{ env.WORKING_DIRECTORY }}
run: |
npm run build
npm run publish:cdn
env:
TOAST_CLOUD_TENANTID: ${{ secrets.TOAST_CLOUD_TENANTID }}
TOAST_CLOUD_STORAGEID: ${{ secrets.TOAST_CLOUD_STORAGEID }}
TOAST_CLOUD_USERNAME: ${{ secrets.TOAST_CLOUD_USERNAME }}
TOAST_CLOUD_PASSWORD: ${{ secrets.TOAST_CLOUD_PASSWORD }}
================================================
FILE: .github/workflows/publish-docs.yml
================================================
name: Publish docs
on: [workflow_dispatch]
env:
WORKING_DIRECTORY: ./apps/calendar
jobs:
publish-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get the package version
id: cpv
uses: PostHog/check-package-version@v2
with:
path: ${{ env.WORKING_DIRECTORY }}
- name: Install dependencies
uses: ./.github/composite-actions/install-dependencies
- name: Update the relative links in README
run: |
PACKAGES=core npm run update:readme
- name: Prebuild docs
working-directory: ${{ env.WORKING_DIRECTORY }}
run: |
npm run docs:prebuild
- name: Change node version to 10
uses: actions/setup-node@v3
with:
node-version: '10'
registry-url: https://registry.npmjs.org/
- name: Install tuidoc
run: |
npm install -g @toast-ui/doc
shell: bash
- name: Build docs
working-directory: ${{ env.WORKING_DIRECTORY }}
run: |
tuidoc
shell: bash
- name: Switch branch
run: |
git stash
git switch gh-pages
- name: Remove previous docs
run: |
rm -rf latest
rm -rf ${{ steps.cpv.outputs.committed-version }}
- name: Commit docs
working-directory: ${{ env.WORKING_DIRECTORY }}
run: |
git config --local user.email "dohyung.ahn@nhn.com"
git config --local user.name "Dohyung Ahn"
mv -i _latest ../../latest
mv _${{ steps.cpv.outputs.committed-version }} ../../${{ steps.cpv.outputs.committed-version }}
git add -A
git commit -m ${{ steps.cpv.outputs.committed-version }}
- name: Publish new docs
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: gh-pages
- name: Back to main branch
run: |
git switch main
- name: Restore Node.js version to 16
uses: actions/setup-node@v3
with:
node-version: '16'
registry-url: https://registry.npmjs.org/
cache: 'npm'
================================================
FILE: .github/workflows/publish-wrappers.yml
================================================
name: Publish wrapper
on: [workflow_dispatch]
env:
WORKING_DIRECTORY: ./apps/calendar
REACT_WRAPPER_DIRECTORY: ./apps/react-calendar
VUE_WRAPPER_DIRECTORY: ./apps/vue-calendar
jobs:
publish-wrapper:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v3
- name: Install root dependencies
uses: ./.github/composite-actions/install-dependencies
- name: Use Node.js 16.x
uses: actions/setup-node@v1
with:
node-version: '16.x'
registry-url: https://registry.npmjs.org/
- name: Build core
working-directory: ${{ env.WORKING_DIRECTORY }}
run: |
npm run build
- name: Get the package version
id: version
uses: PostHog/check-package-version@v2
with:
path: ${{ env.WORKING_DIRECTORY }}/
- name: Update version of wrappers in package.json
working-directory: ${{ env.WORKING_DIRECTORY }}
run: |
npm run update:wrapper
- name: Update lock file of react wrapper
working-directory: ${{ env.REACT_WRAPPER_DIRECTORY }}
run: |
npm install
- name: Build react wrapper
working-directory: ${{ env.REACT_WRAPPER_DIRECTORY }}
run: |
npm run build
- name: Update lock file of Vue wrapper
working-directory: ${{ env.VUE_WRAPPER_DIRECTORY }}
run: |
npm install
- name: Build vue wrapper
working-directory: ${{ env.VUE_WRAPPER_DIRECTORY }}
run: |
npm run build
- name: Commit files
run: |
rm -rf ./apps/react-calendar/package-lock.json
rm -rf ./apps/vue-calendar/package-lock.json
git config --local user.name "lja1018"
git config --local user.email "jaeeon.lim@nhn.com"
git add .
git commit -m "chore: update version of wrappers to v${{ steps.version.outputs.committed-version }}"
- name: Push version update commit
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: main
- name: Push new version tags
run: |
git tag react-calendar@${{ steps.version.outputs.committed-version }}
git tag vue-calendar@${{ steps.version.outputs.committed-version }}
git push origin react-calendar@${{ steps.version.outputs.committed-version }}
git push origin vue-calendar@${{ steps.version.outputs.committed-version }}
- name: Update the relative links in README
run: |
PACKAGES=react,vue npm run update:readme
- name: Publish react wrapper
working-directory: ${{ env.REACT_WRAPPER_DIRECTORY }}
run: |
npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish vue wrapper
working-directory: ${{ env.VUE_WRAPPER_DIRECTORY }}
run: |
npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
================================================
FILE: .github/workflows/test.yml
================================================
name: Lint and test
on:
pull_request:
branches: [main]
workflow_call:
jobs:
lint:
name: Lint & Type Checking
runs-on: ubuntu-latest
steps:
- name: Checkout next branch
uses: actions/checkout@v3
- name: Install dependencies
uses: ./.github/composite-actions/install-dependencies
- name: Lint & Type Checking
run: |
npm run lint
test-jest:
name: Test jest
needs: [lint]
runs-on: ubuntu-latest
steps:
- name: Checkout next branch
uses: actions/checkout@v3
- name: Install dependencies
uses: ./.github/composite-actions/install-dependencies
- name: run unit test
run: |
npm run test
test-playwright:
name: Test playwright
needs: [lint]
runs-on: ubuntu-latest
steps:
- name: Checkout next branch
uses: actions/checkout@v3
- name: Install dependencies
uses: ./.github/composite-actions/install-dependencies
- name: Install playwright dependencies
run: |
npx playwright install --with-deps
- name: Build storybook
run: |
npm run storybook:build -w "@toast-ui/calendar"
- name: Run E2E test
run: |
npm run test:playwright
================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
screenshots
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
node_modules
# Bower Components
bower_components
lib
# IDEA
.idea
*.iml
# Window
Thumbs.db
Desktop.ini
# MAC
.DS_Store
# SVN
.svn
# eclipse
.project
.metadata
# build
build/
storybook-static/
dist/
apps/calendar/types/
tmpdoc/
# etc
*.swp
etc
temp
api
doc
report
karma.conf.local.js
.tern-project
.tern-port
*.vim
.\#*
.vscode/
test-results/
stats.json
================================================
FILE: .husky/.gitignore
================================================
_
================================================
FILE: .husky/pre-commit
================================================
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
================================================
FILE: .prettierignore
================================================
*.md
*.html
================================================
FILE: .prettierrc
================================================
{
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "es5",
"arrowParens": "always",
"endOfLine": "lf",
"bracketSpacing": true,
"requirePragma": false,
"insertPragma": false,
"proseWrap": "preserve",
"vueIndentScriptAndStyle": false
}
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
education, socio-economic status, nationality, personal appearance, race,
religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at dl_javascript@nhn.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to TOAST UI
First off, thanks for taking the time to contribute! 🎉 😘 ✨
The following is a set of guidelines for contributing to TOAST UI. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
## Reporting Bugs
Bugs are tracked as [GitHub issues](https://github.com/nhn/tui.calendar/issues). Search the issue list and try to reproduce on [demo](https://nhn.github.io/tui.calendar/latest/tutorial-00-calendar-app) before you create an issue. When you create an issue, please provide the following information by filling in the template.
Explain the problem and include additional details to help maintainers reproduce the problem:
* **Use a clear and descriptive title** for the issue to identify the problem.
* **Describe the exact steps which reproduce the problem** in as many details as possible. Don't just say what you did, but explain how you did it. For example, if you moved the cursor to the end of a line, explain if you used a mouse or a keyboard.
* **Provide specific examples to demonstrate the steps.** Include links to files or GitHub projects, or copy/paste-able snippets, which you use in those examples. If you're providing snippets on the issue, use Markdown code blocks.
* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.
* **Explain which behavior you expected to see instead and why.**
* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem.
## Suggesting Enhancements
In case you want to suggest for TOAST UI Calendar, please follow this guideline to help maintainers and the community understand your suggestion.
Before creating suggestions, please check [issue list](https://github.com/nhn/tui.calendar/labels/Type:%20Enhancement) if there's already a request.
Create an issue and provide the following information:
* **Use a clear and descriptive title** for the issue to identify the suggestion.
* **Provide a step-by-step description of the suggested enhancement** in as many details as possible.
* **Provide specific examples to demonstrate the steps.** Include copy/paste-able snippets which you use in those examples, as Markdown code blocks.
* **Include screenshots and animated GIFs** which helps demonstrate the steps or point out the part of TOAST UI Calendar which the suggestion is related to.
* **Explain why this enhancement would be useful** to most TOAST UI users.
* **List some other applications where this enhancement exists.**
## First Code Contribution
Unsure where to begin contributing to TOAST UI? You can start by looking through these `document`, `good first issue` and `help wanted` issues:
* **document issues**: issues which should be reviewed or improved.
* **good first issues**: issues which should only require a few lines of code, and a test or two.
* **help wanted issues**: issues which should be a bit more involved than beginner issues.
## Pull Requests
### Development WorkFlow
- Set up your development environment
- Make change from a right branch
- Be sure the code passes `npm run lint`, `npm run test`, `npm run test:playwright`
- Make a pull request
### Development environment
- Prepare your machine Node.js 16+ and it's packages installed.
- Checkout to the right branch
- Install dependencies by `npm install`
- Start development by `npm run develop`
- For wrappers, `npm run develop --workspace @toast-ui/react-calendar` or `npm run develop --workspace @toast-ui/vue-calendar`
### Make changes
#### Checkout a branch
- **main**: PR base branch. merge features, updates for next minor or major release.
- **v1**: Legacy version of the project.
- **gh-pages**: API docs, examples and demo
#### Check Code Style
Run `npm run lint` and make sure all the tests pass.
#### Test
Run `npm run test` and verify all the tests pass.
If you are adding new commands or features, they must include tests.
If you are changing functionality, update the tests if you need to.
#### Commit
Follow our [commit message conventions](./docs/COMMIT_MESSAGE_CONVENTION.md).
### Yes! Pull request
Make your pull request, then describe your changes.
#### Title
Follow other PR title format on below.
```
<Type>: Short Description (fix #111)
<Type>: Short Description (fix #123, #111, #122)
<Type>: Short Description (ref #111)
```
* capitalize first letter of Type
* use present tense: 'change' not 'changed' or 'changes'
#### Description
If it has related to issues, add links to the issues(like `#123`) in the description.
Fill in the [Pull Request Template](./docs/PULL_REQUEST_TEMPLATE.md) by check your case.
## Code of Conduct
This project and everyone participating in it is governed by the [Code of Conduct](./CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to dl_javascript@github.com.
> This Guide is base on [atom contributing guide](https://github.com/atom/atom/blob/master/CONTRIBUTING.md), [CocoaPods](http://guides.cocoapods.org/contributing/contribute-to-cocoapods.html) and [ESLint](http://eslint.org/docs/developer-guide/contributing/pull-requests)
[demo]:https://nhn.github.io/tui.calendar/latest
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 NHN Corp.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
# 
> 🍞📅 A JavaScript calendar that is full featured. Now your service just got the customizable calendar.
[](https://www.npmjs.com/package/@toast-ui/calendar)
[](https://github.com/nhn/tui.calendar/blob/main/LICENSE)
[](https://github.com/nhn/tui.calendar/labels/help%20wanted)
[](https://github.com/nhn)
## 🚩 Table of Contents
- [📦 Packages](#-packages)
- [📙 Documents](#-documents)
- [Collect statistics on the use of open source](#collect-statistics-on-the-use-of-open-source)
- [📅 Features](#-features)
- [✨ Monthly, Weekly, Daily and Various View Types](#-monthly-weekly-daily-and-various-view-types)
- [Easy to Use: Dragging and Resizing a Schedule](#easy-to-use-dragging-and-resizing-a-schedule)
- [Ready to Use: Default Popups](#ready-to-use-default-popups)
- [🎨 Other Features](#-other-features)
- [💬 Contributing](#-contributing)
- [🌏 Browser Support](#-browser-support)
- [🔩 Dependencies](#-dependencies)
- [🍞 TOAST UI Family](#-toast-ui-family)
- [🚀 Used By](#-used-by)
- [📜 License](#-license)
## 📦 Packages
The functionality of TOAST UI Calendar is available when using the Plain JavaScript, React, Vue Component.
- [@toast-ui/calendar](/apps/calendar) - Plain JavaScript component implemented by [NHN Cloud](https://github.com/nhn).
- [@toast-ui/react-calendar](/apps/react-calendar) - React wrapper component implemented by [NHN Cloud](https://github.com/nhn).
- [@toast-ui/vue-calendar](/apps/vue-calendar) - Vue wrapper component implemented by [NHN Cloud](https://github.com/nhn).
## 📙 Documents
- [English](./docs/README.md)
- [Korean](./docs/ko/README.md)
## Collect statistics on the use of open source
TOAST UI Calendar applies Google Analytics (GA) to collect statistics on the use of open source, in order to identify how widely TOAST UI Calendar is used throughout the world. It also serves as important index to determine the future course of projects. location.hostname (e.g. > “ui.toast.com") is to be collected and the sole purpose is nothing but to measure statistics on the usage.
To disable GA, refer to the docs below.
- [TOAST UI Calendar](/docs/en/guide/getting-started.md#disable-to-collect-hostname-for-google-analyticsga)
- [TOAST UI Calendar for React](/apps/react-calendar/docs/en/guide/getting-started.md#disable-to-collect-hostname-for-google-analyticsga)
- [TOAST UI Calendar for Vue](/apps/vue-calendar/docs/en/guide/getting-started.md#disable-to-collect-hostname-for-google-analyticsga)
## 📅 Features
### ✨ Monthly, Weekly, Daily and Various View Types
| Monthly | Weekly |
| --- | --- |
|  |  |
| Daily | 2 Weeks |
| --- | --- |
|  |  |
### Easy to Use: Dragging and Resizing a Schedule
| Dragging | Resizing |
| --- | --- |
|  |  |
### Ready to Use: Default Popups
| Creation Popup | Detail Popup |
| --- | --- |
|  |  |
## 🎨 Other Features
- Supports various view types: daily, weekly, monthly(6 weeks, 2 weeks, 3 weeks)
- Supports efficient management of milestone and task schedules
- Supports the narrow width of weekend
- Supports changing start day of week
- Supports customizing the date and schedule information UI(including a header and a footer of grid cell)
- Supports adjusting a schedule by mouse dragging
- Supports customizing UI by theme
## 💬 Contributing
- [Code of Conduct](/CODE_OF_CONDUCT.md)
- [Contributing Guidelines](/CONTRIBUTING.md)
- [Commit Message Convention](/docs/COMMIT_MESSAGE_CONVENTION.md)
- [Issue Guidelines](/docs/ISSUE_TEMPLATE.md)
## 🌏 Browser Support
| <img src="https://user-images.githubusercontent.com/1215767/34348387-a2e64588-ea4d-11e7-8267-a43365103afe.png" alt="Chrome" width="16px" height="16px" /> Chrome | <img src="https://user-images.githubusercontent.com/1215767/34348590-250b3ca2-ea4f-11e7-9efb-da953359321f.png" alt="IE" width="16px" height="16px" /> Internet Explorer | <img src="https://user-images.githubusercontent.com/1215767/34348380-93e77ae8-ea4d-11e7-8696-9a989ddbbbf5.png" alt="Edge" width="16px" height="16px" /> Edge | <img src="https://user-images.githubusercontent.com/1215767/34348394-a981f892-ea4d-11e7-9156-d128d58386b9.png" alt="Safari" width="16px" height="16px" /> Safari | <img src="https://user-images.githubusercontent.com/1215767/34348383-9e7ed492-ea4d-11e7-910c-03b39d52f496.png" alt="Firefox" width="16px" height="16px" /> Firefox |
| :---------: | :---------: | :---------: | :---------: | :---------: |
| Latest | 11+ | Latest | Latest | Latest |
## 🔩 Dependencies
- [Preact](https://github.com/preactjs/preact)
- [Immer](https://github.com/immerjs/immer)
- [DOMPurify](https://github.com/cure53/DOMPurify)
- (Optional) [tui-date-picker](https://github.com/nhn/tui.date-picker)
- (Optional) [tui-time-picker](https://github.com/nhn/tui.time-picker)
## 🍞 TOAST UI Family
- [TOAST UI Grid](https://github.com/nhn/tui.grid)
- [TOAST UI Chart](https://github.com/nhn/tui.chart)
- [TOAST UI Editor](https://github.com/nhn/tui.editor)
- [TOAST UI Image-Editor](https://github.com/nhn/tui.image-editor)
- [TOAST UI Components](https://github.com/nhn?q=tui)
## 🚀 Used By
- [NHN Dooray! - Collaboration Service (Project, Messenger, Mail, Calendar, Drive, Wiki, Contacts)](https://dooray.com)
- [NCP - Commerce Platform](https://www.e-ncp.com/)
- [shopby](https://www.godo.co.kr/shopby/main.gd)
- [payco-shopping](https://shopping.payco.com/)
- [iamTeacher](https://teacher.iamservice.net)
- [linder](https://www.linder.kr)
## 📜 License
This software is licensed under the [MIT](/LICENSE) © [NHN Cloud](https://github.com/nhn).
================================================
FILE: apps/calendar/.browserslistrc
================================================
> 1%
last 2 versions
not ie <= 10
================================================
FILE: apps/calendar/.lintstagedrc.js
================================================
module.exports = {
'**/*.js': 'eslint --fix',
'**/*.{ts,tsx}': [() => 'npm run check-types', 'eslint --fix', 'jest --bail --findRelatedTests'],
'**/*.css': 'stylelint',
};
================================================
FILE: apps/calendar/.storybook/main.js
================================================
const path = require('path');
module.exports = {
core: {
builder: 'webpack5',
},
stories: ['../**/*.stories.@(ts|tsx)'],
babel: async (config) => {
// Replace storybook babel preset & plugins with custom ones
config.presets.splice(config.presets.length - 1, 1, [
require.resolve('@babel/preset-typescript'),
{ jsxPragma: 'h', jsxPragmaFrag: 'Fragment' },
]);
config.plugins.splice(config.plugins.length - 1, 1, [
require.resolve('@babel/plugin-transform-react-jsx'),
{ pragma: 'h', pragmaFrag: 'Fragment' },
'preset',
]);
return config;
},
webpackFinal: async (config) => {
config.module.rules = config.module.rules
.filter((rule) => !(rule?.test?.test('.css') ?? false))
.concat([
{
test: /\.css$/,
include: /node_modules/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
},
},
],
},
{
test: /\.css$/,
exclude: /node_modules/,
sideEffects: true,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
},
},
require.resolve('postcss-loader'),
],
},
]);
Object.assign(config.resolve.alias, {
'core-js/modules': path.resolve(__dirname, '../../../node_modules/core-js/modules'),
'@src': path.resolve(__dirname, '../src/'),
'@t': path.resolve(__dirname, '../src/types/'),
'@stories': path.resolve(__dirname, '../stories/'),
});
return config;
},
};
================================================
FILE: apps/calendar/.storybook/manager.js
================================================
import { addons } from '@storybook/addons';
import calendarTheme from './theme';
addons.setConfig({
theme: calendarTheme,
});
================================================
FILE: apps/calendar/.storybook/preview.js
================================================
import 'preact/debug';
import '@src/css/index.css';
import 'tui-date-picker/dist/tui-date-picker.css';
import 'tui-time-picker/dist/tui-time-picker.css';
export const parameters = {
layout: 'fullscreen',
};
================================================
FILE: apps/calendar/.storybook/theme.js
================================================
import { create } from '@storybook/theming';
export default create({
base: 'light',
brandTitle: 'TOAST UI Calendar',
brandUrl: 'https://ui.toast.com/tui-calendar',
brandImage: 'https://user-images.githubusercontent.com/26706716/39230183-7f8ff186-48a0-11e8-8d9c-9699d2d0e471.png',
});
================================================
FILE: apps/calendar/README.md
================================================
# 
> A JavaScript calendar that is full featured. Now your service just got the customizable calendar.
[](https://www.npmjs.com/package/@toast-ui/calendar)
[](https://github.com/nhn/tui.calendar/blob/master/LICENSE)
[](https://github.com/nhn/tui.calendar/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
[](https://github.com/nhn)
## 🚩 Table of Contents
- [📙 Documents](#-documents)
- [Collect statistics on the use of open source](#collect-statistics-on-the-use-of-open-source)
- [💾 Install](#-install)
- [Using npm](#using-npm)
- [Via Contents Delivery Network (CDN)](#via-contents-delivery-network-cdn)
- [Download Source Files](#download-source-files)
- [📅 Usage](#-usage)
- [Load](#load)
- [Implement](#implement)
- [🔧 Pull Request Steps](#-pull-request-steps)
- [Setup](#setup)
- [Develop](#develop)
- [Pull Request](#pull-request)
- [💬 Contributing](#-contributing)
- [📜 License](#-license)
## 📙 Documents
- [English](/docs/README.md)
- [Korean](/docs/ko/README.md)
## Collect statistics on the use of open source
TOAST UI Calendar applies Google Analytics (GA) to collect statistics on the use of open source, in order to identify how widely TOAST UI Calendar is used throughout the world. It also serves as important index to determine the future course of projects. location.hostname (e.g. > “ui.toast.com") is to be collected and the sole purpose is nothing but to measure statistics on the usage.
To disable GA, set the [`usageStatistics` option](/docs/en/apis/options.md#usagestatistics) to `false`:
```js
const calendar = new Calendar('#calendar', {
usageStatistics: false
});
```
## 💾 Install
### Using npm
```sh
npm install --save @toast-ui/calendar
```
### Via Contents Delivery Network (CDN)
TOAST UI products are available over the CDN powered by [NHN Cloud](https://www.toast.com).
```html
<link rel="stylesheet" href="https://uicdn.toast.com/calendar/latest/toastui-calendar.min.css" />
<script src="https://uicdn.toast.com/calendar/latest/toastui-calendar.min.js"></script>
<!-- To get bundle file for legacy browser -->
<!-- <script src="https://uicdn.toast.com/calendar /latest/toastui-calendar.ie11.min.js"></script> -->
<!-- Import as es module -->
<!-- <script type="module" src="https:// uicdn.toast.com/calendar/latest/toastui-calendar.mjs"></script> -->
```
If you want to use a specific version, use the tag name instead of `latest` in the url's path.
The CDN directory has the following structure.
```
- uicdn.toast.com/
├─ calendar/
│ ├─ latest
│ │ ├─ toastui-calendar.css
│ │ ├─ toastui-calendar.js
│ │ ├─ toastui-calendar.min.css
│ │ ├─ toastui-calendar.min.js
│ │ ├─ toastui-calendar.ie11.js
│ │ ├─ toastui-calendar.ie11.min.js
│ │ │ toastui-calendar.mjs
│ ├─ v2.0.0/
```
### Download Source Files
- [Download all sources for each version](https://github.com/nhn/tui.calendar/releases)
## 📅 Usage
### Load
TOAST UI Calendar can be instantiated through the constructor function. There are three ways to access the constructor function depending on the environment.
```js
/* ES6 module in Node.js environment */
import Calendar from '@toast-ui/calendar';
import '@toast-ui/calendar/dist/toastui-calendar.min.css';
```
```js
/* CommonJS in Node.js environment */
const Calendar = require('@toast-ui/calendar');
require('@toast-ui/calendar/dist/toastui-calendar.min.css');
```
```js
/* in the browser environment namespace */
const Calendar = tui.Calendar;
```
### Implement
```html
<div id="calendar" style="height: 800px"></div>
```
```javascript
const calendar = new Calendar('#calendar', {
defaultView: 'week',
template: {
time(event) {
const { start, end, title } = event;
return `<span style="color: white;">${formatTime(start)}~${formatTime(end)} ${title}</span>`;
},
allday(event) {
return `<span style="color: gray;">${event.title}</span>`;
},
},
calendars: [
{
id: 'cal1',
name: 'Personal',
backgroundColor: '#03bd9e',
},
{
id: 'cal2',
name: 'Work',
backgroundColor: '#00a9ff',
},
],
});
```
## 🔧 Pull Request Steps
TOAST UI products are open source, so you can create a pull request(PR) after you fix issues.
Run npm scripts and develop yourself with the following process.
### Setup
Fork `main` branch into your personal repository.
Clone it to local computer. Install node modules.
Before starting development, you should check to have any errors.
``` sh
git clone https://github.com/{your-personal-repo}/[[repo name]].git
cd [[repo name]]
npm install
```
### Develop
Let's start development!
### Pull Request
Before PR, check to test lastly and then check any errors.
If it has no error, commit and then push it!
For more information on PR's step, please see links of Contributing section.
## 💬 Contributing
- [Code of Conduct](/CODE_OF_CONDUCT.md)
- [Contributing Guidelines](/CONTRIBUTING.md)
- [Commit Message Convention](/docs/COMMIT_MESSAGE_CONVENTION.md)
## 📜 License
This software is licensed under the [MIT](/LICENSE) © [NHN Cloud](https://github.com/nhn).
================================================
FILE: apps/calendar/examples/00-calendar-app.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar App Demo</title>
<link
rel="stylesheet"
href="https://uicdn.toast.com/tui.time-picker/latest/tui-time-picker.min.css"
/>
<link
rel="stylesheet"
href="https://uicdn.toast.com/tui.date-picker/latest/tui-date-picker.min.css"
/>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
</head>
<body>
<div class="app-container code-html">
<header class="header">
<a href="https://github.com/nhn/tui.calendar">
<img
alt="TOAST UI Calendar Brand Image"
src="./images/img-bi.png"
srcset="./images/img-bi@2x.png 2x, ./images/img-bi@3x.png 3x"
/>
</a>
</header>
<article class="content">
<aside class="sidebar">
<div class="sidebar-item">
<input class="checkbox-all" type="checkbox" id="all" value="all" checked />
<label class="checkbox checkbox-all" for="all">View all</label>
</div>
<hr />
<div class="sidebar-item">
<input type="checkbox" id="1" value="1" checked />
<label class="checkbox checkbox-calendar checkbox-1" for="1">My Calendar</label>
</div>
<div class="sidebar-item">
<input type="checkbox" id="2" value="2" checked />
<label class="checkbox checkbox-calendar checkbox-2" for="2">Work</label>
</div>
<div class="sidebar-item">
<input type="checkbox" id="3" value="3" checked />
<label class="checkbox checkbox-calendar checkbox-3" for="3">Family</label>
</div>
<div class="sidebar-item">
<input type="checkbox" id="4" value="4" checked />
<label class="checkbox checkbox-calendar checkbox-4" for="4">Friends</label>
</div>
<div class="sidebar-item">
<input type="checkbox" id="5" value="5" checked />
<label class="checkbox checkbox-calendar checkbox-5" for="5">Travel</label>
</div>
<hr />
<div class="app-footer">© NHN Cloud Corp.</div>
</aside>
<section class="app-column">
<nav class="navbar">
<div class="dropdown">
<div class="dropdown-trigger">
<button
class="button is-rounded"
aria-haspopup="true"
aria-controls="dropdown-menu"
>
<span class="button-text"></span>
<span
class="dropdown-icon toastui-calendar-icon toastui-calendar-ic-dropdown-arrow"
></span>
</button>
</div>
<div class="dropdown-menu">
<div class="dropdown-content">
<a href="#" class="dropdown-item" data-view-name="month">Monthly</a>
<a href="#" class="dropdown-item" data-view-name="week">Weekly</a>
<a href="#" class="dropdown-item" data-view-name="day">Daily</a>
</div>
</div>
</div>
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="
./images/ic-arrow-line-left@2x.png 2x,
./images/ic-arrow-line-left@3x.png 3x
"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
<div class="nav-checkbox">
<input class="checkbox-collapse" type="checkbox" id="collapse" value="collapse" />
<label for="collapse">Collapse duplicate events and disable the detail popup</label>
</div>
</nav>
<main id="app"></main>
</section>
</article>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="https://uicdn.toast.com/tui.time-picker/latest/tui-time-picker.min.js"></script>
<script src="https://uicdn.toast.com/tui.date-picker/latest/tui-date-picker.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script src="./scripts/app.js"></script>
</body>
</html>
================================================
FILE: apps/calendar/examples/01-monthly-view-basic.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Monthly View Basic</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'month',
calendars: MOCK_CALENDARS,
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
range.textContent = getNavbarRange(cal.getDateRangeStart(), cal.getDateRangeEnd(), 'month');
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/02-monthly-view-2weeks.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Monthly View Basic</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'month',
calendars: MOCK_CALENDARS,
month: {
visibleWeeksCount: 2,
},
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
range.textContent = getNavbarRange(cal.getDateRangeStart(), cal.getDateRangeEnd(), 'week');
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/03-monthly-view-3weeks.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Monthly View Basic</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'month',
calendars: MOCK_CALENDARS,
month: {
visibleWeeksCount: 3,
},
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
range.textContent = getNavbarRange(cal.getDateRangeStart(), cal.getDateRangeEnd(), 'week');
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/04-weekly-view.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Weekly View</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'week',
calendars: MOCK_CALENDARS,
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
var viewName = cal.getViewName();
range.textContent = getNavbarRange(
cal.getDateRangeStart(),
cal.getDateRangeEnd(),
viewName
);
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/05-weekly-view-no-event-view.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Weekly View (No Event View)</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'week',
calendars: MOCK_CALENDARS,
week: {
taskView: true,
eventView: false,
},
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
var viewName = cal.getViewName();
range.textContent = getNavbarRange(
cal.getDateRangeStart(),
cal.getDateRangeEnd(),
viewName
);
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/06-daily-view.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Daily View</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'day',
calendars: MOCK_CALENDARS,
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
var viewName = cal.getViewName();
range.textContent = getNavbarRange(
cal.getDateRangeStart(),
cal.getDateRangeEnd(),
viewName
);
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/07-narrow-weekends.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Narrow Weekends</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded switch-view">Switch View (Monthly / Weekly)</button>
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'month',
calendars: MOCK_CALENDARS,
month: {
narrowWeekend: true,
},
week: {
narrowWeekend: true,
},
});
</script>
<script type="text/javascript">
var switchButton = $('.switch-view');
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
var viewName = cal.getViewName();
range.textContent = getNavbarRange(
cal.getDateRangeStart(),
cal.getDateRangeEnd(),
viewName
);
}
switchButton.addEventListener('click', function () {
if (cal.getViewName() === 'month') {
cal.changeView('week');
} else {
cal.changeView('month');
}
displayRenderRange();
});
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/08-hidden-weekends.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Hidden Weekends</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded switch-view">Switch View (Monthly / Weekly)</button>
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'month',
calendars: MOCK_CALENDARS,
month: {
workweek: true,
},
week: {
workweek: true,
},
});
</script>
<script type="text/javascript">
var switchButton = $('.switch-view');
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
var viewName = cal.getViewName();
range.textContent = getNavbarRange(
cal.getDateRangeStart(),
cal.getDateRangeEnd(),
viewName
);
}
switchButton.addEventListener('click', function () {
if (cal.getViewName() === 'month') {
cal.changeView('week');
} else {
cal.changeView('month');
}
displayRenderRange();
});
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/09-timezone.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Timezone (Weekly View)</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'week',
calendars: MOCK_CALENDARS,
timezone: {
zones: [
{
timezoneName: 'Asia/Seoul',
displayLabel: 'UTC+09',
tooltip: 'Seoul',
},
{
timezoneName: 'Europe/London',
displayLabel: 'UTC+00',
tooltip: 'London',
},
],
},
week: {
showTimezoneCollapseButton: true,
},
theme: {
week: {
dayGridLeft: {
width: '8rem',
},
timeGridLeft: {
width: '8rem',
},
},
},
});
cal.on('clickTimezonesCollapseBtn', function (prevCollapsedState) {
cal.setOptions({
week: {
timezonesCollapsed: !prevCollapsedState,
},
});
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
var viewName = cal.getViewName();
range.textContent = getNavbarRange(
cal.getDateRangeStart(),
cal.getDateRangeEnd(),
viewName
);
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/10-theme-common.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Common Theme</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'month',
calendars: MOCK_CALENDARS,
theme: {
// NOTE: Not every theme is not included. For more info, check the theme docs.
common: {
backgroundColor: '#8de0cd',
border: '1px solid #818545',
gridSelection: {
backgroundColor: 'rgba(81, 230, 92, 0.05)',
border: '1px dotted #515ce6',
},
saturday: {
color: 'rgba(64, 64, 255, 0.5)',
},
today: {
color: '#ff4194',
},
},
},
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
var viewName = cal.getViewName();
range.textContent = getNavbarRange(
cal.getDateRangeStart(),
cal.getDateRangeEnd(),
viewName
);
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/11-theme-monthly.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Theme for Weekly View</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'month',
calendars: MOCK_CALENDARS,
// NOTE: Not every theme is not included. For more info, check the theme docs.
theme: {
month: {
dayName: {
borderLeft: 'none',
backgroundColor: 'rgba(51, 51, 51, 0.4)',
},
moreView: {
border: '1px solid grey',
boxShadow: '0 2px 6px 0 grey',
backgroundColor: 'white',
width: 320,
height: 200,
},
weekend: {
backgroundColor: 'rgba(255, 64, 64, 0.4)',
},
gridCell: {
footerHeight: 31,
},
},
},
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
var viewName = cal.getViewName();
range.textContent = getNavbarRange(
cal.getDateRangeStart(),
cal.getDateRangeEnd(),
viewName
);
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/12-theme-weekly.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Theme for Weekly View</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'week',
calendars: MOCK_CALENDARS,
timezone: {
zones: [
{
timezoneName: 'Asia/Seoul',
displayLabel: 'UTC+09',
tooltip: 'Seoul',
},
{
timezoneName: 'Europe/London',
displayLabel: 'UTC+00',
tooltip: 'London',
},
],
},
// NOTE: Not every theme is not included. For more info, check the theme docs.
theme: {
week: {
dayName: {
borderLeft: 'none',
borderTop: '1px dotted red',
borderBottom: '1px dotted red',
backgroundColor: 'rgba(81, 92, 230, 0.05)',
},
dayGrid: {
backgroundColor: 'rgba(81, 92, 230, 0.05)',
},
dayGridLeft: {
borderRight: 'none',
backgroundColor: 'rgba(81, 92, 230, 0.05)',
width: '144px',
},
timeGridLeft: {
borderRight: 'none',
backgroundColor: 'rgba(81, 92, 230, 0.05)',
width: '144px',
},
timeGridLeftAdditionalTimezone: {
backgroundColor: '#e5e5e5',
},
timeGridHalfHourLine: {
borderBottom: '1px dotted #e5e5e5',
},
nowIndicatorPast: {
border: '1px dashed red',
},
futureTime: {
color: 'red',
},
},
},
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
var viewName = cal.getViewName();
range.textContent = getNavbarRange(
cal.getDateRangeStart(),
cal.getDateRangeEnd(),
viewName
);
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/13-template-monthly.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Templates for Monthly View</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'month',
calendars: MOCK_CALENDARS,
template: {
monthGridHeader: function (data) {
var date = parseInt(data.date.split('-')[2], 10);
return (
'<span class="calendar-month-header" style="margin-left: 4px;">' +
(data.month + 1) +
'/' +
date +
'</span>'
);
},
monthGridHeaderExceed: function (hiddenEvents) {
return (
'<span class="calendar-month-header-exceed" style="font-size: 0.8rem">' +
'+' +
hiddenEvents +
'</span>'
);
},
monthDayName: function (data) {
var label = data.label;
if (data.day === 5) {
label = '🎉 TGIF';
}
return '<span class="calendar-month-day-name">' + label + '</span>';
},
},
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
var viewName = cal.getViewName();
range.textContent = getNavbarRange(
cal.getDateRangeStart(),
cal.getDateRangeEnd(),
viewName
);
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/14-template-weekly.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Template for Weekly View</title>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body k>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'week',
calendars: MOCK_CALENDARS,
timezone: {
zones: [
{
timezoneName: 'Asia/Seoul',
displayLabel: 'UTC+09',
tooltip: 'Seoul',
},
{
timezoneName: 'Europe/London',
tooltip: 'London',
},
],
},
theme: {
week: {
dayGridLeft: {
width: '8rem',
},
timeGridLeft: {
width: '8rem',
},
},
},
template: {
milestone: function (event) {
return '<span class="calendar-event-milestone">' + '⛳ ' + event.title + '</span>';
},
milestoneTitle: function () {
return '<strong>Milestones</strong>';
},
task: function (event) {
return '<span class="calendar-event-task">' + '✅ ' + event.title + '</span>';
},
taskTitle: function () {
return '<strong>Tasks</strong>';
},
allday: function (event) {
return '<span class="calendar-event-allday">' + event.title + '</span>';
},
alldayTitle: function () {
return '<strong>All day events</strong>';
},
time: function (event) {
return (
'<span class="calendar-event-time" style="color: #222;">' + event.title + '</span>'
);
},
goingDuration: function (event) {
return (
'<span class="calendar-event-going-duration" style="color: #222;">' +
event.goingDuration +
'</span>'
);
},
comingDuration: function (event) {
return (
'<span class="calendar-event-coming-duration" style="color: #222;">' +
event.comingDuration +
'</span>'
);
},
weekDayName: function (data) {
var date = data.dateInstance.toDate();
return (
'<span class="calendar-event-weekday-name">' +
moment(date).format('MM-DD') +
'</span>'
);
},
weekGridFooterExceed: function (hiddenEvents) {
return (
'<span class="calendar-event-weekgrid-footer-exceed">+' + hiddenEvents + '</span>'
);
},
collapseBtnTitle: function () {
return '⬆️';
},
timezoneDisplayLabel: function (data) {
if (data.displayLabel) {
return data.displayLabel;
}
return String(
data.timezoneOffset > 0 ? '+' + data.timezoneOffset : data.timezoneOffset
);
},
timegridNowIndicatorLabel: function (data) {
return 'Now: ' + moment(data.time.toDate()).format('hh:mm');
},
},
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
var viewName = cal.getViewName();
range.textContent = getNavbarRange(
cal.getDateRangeStart(),
cal.getDateRangeEnd(),
viewName
);
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/15-template-popup.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>TOAST UI Calendar Example - Theme for Popup</title>
<link
rel="stylesheet"
href="https://uicdn.toast.com/tui.time-picker/latest/tui-time-picker.min.css"
/>
<link
rel="stylesheet"
href="https://uicdn.toast.com/tui.date-picker/latest/tui-date-picker.min.css"
/>
<link rel="stylesheet" href="../dist/toastui-calendar.css" />
<link rel="stylesheet" href="./styles/reset.css" />
<link rel="stylesheet" href="./styles/app.css" />
<link rel="stylesheet" href="./styles/icons.css" />
<style>
.navbar {
padding: 0;
}
</style>
</head>
<body>
<div class="app-container code-html">
<header class="header">
<nav class="navbar">
<button class="button is-rounded today">Today</button>
<button class="button is-rounded prev">
<img
alt="prev"
src="./images/ic-arrow-line-left.png"
srcset="./images/ic-arrow-line-left@2x.png 2x, ./images/ic-arrow-line-left@3x.png 3x"
/>
</button>
<button class="button is-rounded next">
<img
alt="prev"
src="./images/ic-arrow-line-right.png"
srcset="
./images/ic-arrow-line-right@2x.png 2x,
./images/ic-arrow-line-right@3x.png 3x
"
/>
</button>
<span class="navbar--range"></span>
</nav>
</header>
<main id="app"></main>
</div>
<script src="https://uicdn.toast.com/tui.time-picker/latest/tui-time-picker.min.js"></script>
<script src="https://uicdn.toast.com/tui.date-picker/latest/tui-date-picker.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.1.8/chance.min.js"></script>
<script src="../dist/toastui-calendar.ie11.min.js"></script>
<script src="./scripts/mock-data.js"></script>
<script src="./scripts/utils.js"></script>
<script type="text/javascript" class="code-js">
var Calendar = window.tui.Calendar;
var cal = new Calendar('#app', {
defaultView: 'month',
calendars: MOCK_CALENDARS,
useFormPopup: true,
useDetailPopup: true,
template: {
popupIsAllday: function () {
return 'All day?';
},
popupStateFree: function () {
return '🏝️ Free';
},
popupStateBusy: function () {
return '🔥 Busy';
},
titlePlaceholder: function () {
return 'Enter title';
},
locationPlaceholder: function () {
return 'Enter location';
},
startDatePlaceholder: function () {
return 'Start date';
},
endDatePlaceholder: function () {
return 'End date';
},
popupSave: function () {
return 'Add Event';
},
popupUpdate: function () {
return 'Update Event';
},
popupEdit: function () {
return 'Modify';
},
popupDelete: function () {
return 'Remove';
},
popupDetailTitle: function (data) {
return 'Detail of ' + data.title;
},
},
});
</script>
<script type="text/javascript">
var todayButton = $('.today');
var prevButton = $('.prev');
var nextButton = $('.next');
var range = $('.navbar--range');
function displayEvents() {
var events = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.clear();
cal.createEvents(events);
}
function displayRenderRange() {
var viewName = cal.getViewName();
range.textContent = getNavbarRange(
cal.getDateRangeStart(),
cal.getDateRangeEnd(),
viewName
);
}
todayButton.addEventListener('click', function () {
cal.today();
displayEvents();
displayRenderRange();
});
prevButton.addEventListener('click', function () {
cal.prev();
displayEvents();
displayRenderRange();
});
nextButton.addEventListener('click', function () {
cal.next();
displayEvents();
displayRenderRange();
});
displayEvents();
displayRenderRange();
</script>
</body>
</html>
================================================
FILE: apps/calendar/examples/scripts/app.js
================================================
/* eslint-disable no-var,prefer-destructuring,prefer-template,no-undef,object-shorthand,no-console */
// for testing IE11 compatibility, this file doesn't use ES6 syntax.
(function (Calendar) {
var cal;
// Constants
var CALENDAR_CSS_PREFIX = 'toastui-calendar-';
var cls = function (className) {
return CALENDAR_CSS_PREFIX + className;
};
// Elements
var navbarRange = $('.navbar--range');
var prevButton = $('.prev');
var nextButton = $('.next');
var todayButton = $('.today');
var dropdown = $('.dropdown');
var dropdownTrigger = $('.dropdown-trigger');
var dropdownTriggerIcon = $('.dropdown-icon');
var dropdownContent = $('.dropdown-content');
var checkboxCollapse = $('.checkbox-collapse');
var sidebar = $('.sidebar');
// App State
var appState = {
activeCalendarIds: MOCK_CALENDARS.map(function (calendar) {
return calendar.id;
}),
isDropdownActive: false,
};
// functions to handle calendar behaviors
function reloadEvents() {
var randomEvents;
cal.clear();
randomEvents = generateRandomEvents(
cal.getViewName(),
cal.getDateRangeStart(),
cal.getDateRangeEnd()
);
cal.createEvents(randomEvents);
}
function getReadableViewName(viewType) {
switch (viewType) {
case 'month':
return 'Monthly';
case 'week':
return 'Weekly';
case 'day':
return 'Daily';
default:
throw new Error('no view type');
}
}
function displayRenderRange() {
var rangeStart = cal.getDateRangeStart();
var rangeEnd = cal.getDateRangeEnd();
navbarRange.textContent = getNavbarRange(rangeStart, rangeEnd, cal.getViewName());
}
function setDropdownTriggerText() {
var viewName = cal.getViewName();
var buttonText = $('.dropdown .button-text');
buttonText.textContent = getReadableViewName(viewName);
}
function toggleDropdownState() {
appState.isDropdownActive = !appState.isDropdownActive;
dropdown.classList.toggle('is-active', appState.isDropdownActive);
dropdownTriggerIcon.classList.toggle(cls('open'), appState.isDropdownActive);
}
function setAllCheckboxes(checked) {
var checkboxes = $$('.sidebar-item > input[type="checkbox"]');
checkboxes.forEach(function (checkbox) {
checkbox.checked = checked;
setCheckboxBackgroundColor(checkbox);
});
}
function setCheckboxBackgroundColor(checkbox) {
var calendarId = checkbox.value;
var label = checkbox.nextElementSibling;
var calendarInfo = MOCK_CALENDARS.find(function (calendar) {
return calendar.id === calendarId;
});
if (!calendarInfo) {
calendarInfo = {
backgroundColor: '#2a4fa7',
};
}
label.style.setProperty(
'--checkbox-' + calendarId,
checkbox.checked ? calendarInfo.backgroundColor : '#fff'
);
}
function update() {
setDropdownTriggerText();
displayRenderRange();
reloadEvents();
}
function bindAppEvents() {
dropdownTrigger.addEventListener('click', toggleDropdownState);
prevButton.addEventListener('click', function () {
cal.prev();
update();
});
nextButton.addEventListener('click', function () {
cal.next();
update();
});
todayButton.addEventListener('click', function () {
cal.today();
update();
});
dropdownContent.addEventListener('click', function (e) {
var targetViewName;
if ('viewName' in e.target.dataset) {
targetViewName = e.target.dataset.viewName;
cal.changeView(targetViewName);
checkboxCollapse.disabled = targetViewName === 'month';
toggleDropdownState();
update();
}
});
checkboxCollapse.addEventListener('change', function (e) {
if ('checked' in e.target) {
cal.setOptions({
week: {
collapseDuplicateEvents: !!e.target.checked,
},
useDetailPopup: !e.target.checked,
});
}
});
sidebar.addEventListener('click', function (e) {
if ('value' in e.target) {
if (e.target.value === 'all') {
if (appState.activeCalendarIds.length > 0) {
cal.setCalendarVisibility(appState.activeCalendarIds, false);
appState.activeCalendarIds = [];
setAllCheckboxes(false);
} else {
appState.activeCalendarIds = MOCK_CALENDARS.map(function (calendar) {
return calendar.id;
});
cal.setCalendarVisibility(appState.activeCalendarIds, true);
setAllCheckboxes(true);
}
} else if (appState.activeCalendarIds.indexOf(e.target.value) > -1) {
appState.activeCalendarIds.splice(appState.activeCalendarIds.indexOf(e.target.value), 1);
cal.setCalendarVisibility(e.target.value, false);
setCheckboxBackgroundColor(e.target);
} else {
appState.activeCalendarIds.push(e.target.value);
cal.setCalendarVisibility(e.target.value, true);
setCheckboxBackgroundColor(e.target);
}
}
});
}
function bindInstanceEvents() {
cal.on({
clickMoreEventsBtn: function (btnInfo) {
console.log('clickMoreEventsBtn', btnInfo);
},
clickEvent: function (eventInfo) {
console.log('clickEvent', eventInfo);
},
clickDayName: function (dayNameInfo) {
console.log('clickDayName', dayNameInfo);
},
selectDateTime: function (dateTimeInfo) {
console.log('selectDateTime', dateTimeInfo);
},
beforeCreateEvent: function (event) {
console.log('beforeCreateEvent', event);
event.id = chance.guid();
cal.createEvents([event]);
cal.clearGridSelections();
},
beforeUpdateEvent: function (eventInfo) {
var event, changes;
console.log('beforeUpdateEvent', eventInfo);
event = eventInfo.event;
changes = eventInfo.changes;
cal.updateEvent(event.id, event.calendarId, changes);
},
beforeDeleteEvent: function (eventInfo) {
console.log('beforeDeleteEvent', eventInfo);
cal.deleteEvent(eventInfo.id, eventInfo.calendarId);
},
});
}
function initCheckbox() {
var checkboxes = $$('input[type="checkbox"]');
checkboxes.forEach(function (checkbox) {
setCheckboxBackgroundColor(checkbox);
});
}
function getEventTemplate(event, isAllday) {
var html = [];
var start = moment(event.start.toDate().toUTCString());
if (!isAllday) {
html.push('<strong>' + start.format('HH:mm') + '</strong> ');
}
if (event.isPrivate) {
html.push('<span class="calendar-font-icon ic-lock-b"></span>');
html.push(' Private');
} else {
if (event.recurrenceRule) {
html.push('<span class="calendar-font-icon ic-repeat-b"></span>');
} else if (event.attendees.length > 0) {
html.push('<span class="calendar-font-icon ic-user-b"></span>');
} else if (event.location) {
html.push('<span class="calendar-font-icon ic-location-b"></span>');
}
html.push(' ' + event.title);
}
return html.join('');
}
// Calendar instance with options
// eslint-disable-next-line no-undef
cal = new Calendar('#app', {
calendars: MOCK_CALENDARS,
useFormPopup: true,
useDetailPopup: true,
eventFilter: function (event) {
var currentView = cal.getViewName();
if (currentView === 'month') {
return ['allday', 'time'].includes(event.category) && event.isVisible;
}
return event.isVisible;
},
template: {
allday: function (event) {
return getEventTemplate(event, true);
},
time: function (event) {
return getEventTemplate(event, false);
},
},
});
// Init
bindInstanceEvents();
bindAppEvents();
initCheckbox();
update();
})(tui.Calendar);
================================================
FILE: apps/calendar/examples/scripts/mock-data.js
================================================
/* eslint-disable */
var MOCK_CALENDARS = [
{
id: '1',
name: 'My Calendar',
color: '#ffffff',
borderColor: '#9e5fff',
backgroundColor: '#9e5fff',
dragBackgroundColor: '#9e5fff',
},
{
id: '2',
name: 'Work',
color: '#ffffff',
borderColor: '#00a9ff',
backgroundColor: '#00a9ff',
dragBackgroundColor: '#00a9ff',
},
{
id: '3',
name: 'Family',
color: '#ffffff',
borderColor: '#DB473F',
backgroundColor: '#DB473F',
dragBackgroundColor: '#DB473F',
},
{
id: '4',
name: 'Friends',
color: '#ffffff',
borderColor: '#03bd9e',
backgroundColor: '#03bd9e',
dragBackgroundColor: '#03bd9e',
},
{
id: '5',
name: 'Travel',
color: '#ffffff',
borderColor: '#bbdc00',
backgroundColor: '#bbdc00',
dragBackgroundColor: '#bbdc00',
},
];
var EVENT_CATEGORIES = ['milestone', 'task'];
function generateRandomEvent(calendar, renderStart, renderEnd) {
function generateTime(event, renderStart, renderEnd) {
var startDate = moment(renderStart.getTime());
var endDate = moment(renderEnd.getTime());
var diffDate = endDate.diff(startDate, 'days');
event.isAllday = chance.bool({ likelihood: 30 });
if (event.isAllday) {
event.category = 'allday';
} else if (chance.bool({ likelihood: 30 })) {
event.category = EVENT_CATEGORIES[chance.integer({ min: 0, max: 1 })];
if (event.category === EVENT_CATEGORIES[1]) {
event.dueDateClass = 'morning';
}
} else {
event.category = 'time';
}
startDate.add(chance.integer({ min: 0, max: diffDate }), 'days');
startDate.hours(chance.integer({ min: 0, max: 23 }));
startDate.minutes(chance.bool() ? 0 : 30);
event.start = startDate.toDate();
endDate = moment(startDate);
if (event.isAllday) {
endDate.add(chance.integer({ min: 0, max: 3 }), 'days');
}
event.end = endDate.add(chance.integer({ min: 1, max: 4 }), 'hour').toDate();
if (!event.isAllday && chance.bool({ likelihood: 20 })) {
event.goingDuration = chance.integer({ min: 30, max: 120 });
event.comingDuration = chance.integer({ min: 30, max: 120 });
if (chance.bool({ likelihood: 50 })) {
event.end = event.start;
}
}
}
function generateNames() {
var names = [];
var i = 0;
var length = chance.integer({ min: 1, max: 10 });
for (; i < length; i += 1) {
names.push(chance.name());
}
return names;
}
var id = chance.guid();
var calendarId = calendar.id;
var title = chance.sentence({ words: 3 });
var body = chance.bool({ likelihood: 20 }) ? chance.sentence({ words: 10 }) : '';
var isReadOnly = chance.bool({ likelihood: 20 });
var isPrivate = chance.bool({ likelihood: 20 });
var location = chance.address();
var attendees = chance.bool({ likelihood: 70 }) ? generateNames() : [];
var recurrenceRule = '';
var state = chance.bool({ likelihood: 50 }) ? 'Busy' : 'Free';
var goingDuration = chance.bool({likelihood: 20}) ? chance.integer({ min: 30, max: 120 }) : 0;
var comingDuration = chance.bool({likelihood: 20}) ? chance.integer({ min: 30, max: 120 }) : 0;
var raw = {
memo: chance.sentence(),
creator: {
name: chance.name(),
avatar: chance.avatar(),
email: chance.email(),
phone: chance.phone(),
},
};
var event = {
id: id,
calendarId: calendarId,
title: title,
body: body,
isReadOnly: isReadOnly,
isPrivate: isPrivate,
location: location,
attendees: attendees,
recurrenceRule: recurrenceRule,
state: state,
goingDuration: goingDuration,
comingDuration: comingDuration,
raw: raw,
}
generateTime(event, renderStart, renderEnd);
if (event.category === 'milestone') {
event.color = '#000'
event.backgroundColor = 'transparent';
event.borderColor = 'transparent';
event.dragBackgroundColor = 'transparent';
}
return event;
}
function generateRandomEvents(viewName, renderStart, renderEnd) {
var i, j;
var event, duplicateEvent;
var events = [];
MOCK_CALENDARS.forEach(function(calendar) {
for (i = 0; i < chance.integer({ min: 20, max: 50 }); i += 1) {
event = generateRandomEvent(calendar, renderStart, renderEnd);
events.push(event);
if (i % 5 === 0) {
for (j = 0; j < chance.integer({min: 0, max: 2}); j+= 1) {
duplicateEvent = JSON.parse(JSON.stringify(event));
duplicateEvent.id += `-${j}`;
duplicateEvent.calendarId = chance.integer({min: 1, max: 5}).toString();
duplicateEvent.goingDuration = 30 * chance.integer({min: 0, max: 4});
duplicateEvent.comingDuration = 30 * chance.integer({min: 0, max: 4});
events.push(duplicateEvent);
}
}
}
});
return events;
}
================================================
FILE: apps/calendar/examples/scripts/utils.js
================================================
/* eslint-disable no-var,prefer-template,no-undef */
var $ = function (selector) {
return document.querySelector(selector);
};
var $$ = function (selector) {
return Array.prototype.slice.call(document.querySelectorAll(selector));
};
function getNavbarRange(tzStart, tzEnd, viewType) {
var start = tzStart.toDate();
var end = tzEnd.toDate();
var middle;
if (viewType === 'month') {
middle = new Date(start.getTime() + (end.getTime() - start.getTime()) / 2);
return moment(middle).format('YYYY-MM');
}
if (viewType === 'day') {
return moment(start).format('YYYY-MM-DD');
}
if (viewType === 'week') {
return moment(start).format('YYYY-MM-DD') + ' ~ ' + moment(end).format('YYYY-MM-DD');
}
throw new Error('no view type');
}
================================================
FILE: apps/calendar/examples/styles/app.css
================================================
@import "https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css";
.header {
padding: 1rem;
border-bottom: 1px solid #bbb;
}
.app-container {
display: flex;
flex-direction: column;
align-items: stretch;
height: 100%;
}
.content {
display: flex;
height: 100%;
}
.sidebar {
display: flex;
flex: 0 1 12rem;
flex-direction: column;
padding: 1.25rem;
background-color: #fafafa;
border-right: 1px solid #d5d5d5;
}
.sidebar hr {
margin: 1rem 0;
}
.sidebar-item + .sidebar-item {
margin-top: 0.75rem;
}
.sidebar .app-footer {
margin-top: auto;
font-size: 0.75rem;
}
.app-column {
display: flex;
flex-direction: column;
flex: 1 0 auto;
}
.app-column nav {
flex: 0 1 4rem;
border-bottom: 1px solid #e5e5e5;
}
#app {
flex: 1 0 auto;
}
.navbar {
display: flex;
align-items: center;
padding: 1rem;
}
.navbar .dropdown {
margin-right: 1rem;
}
.navbar .dropdown .toastui-calendar-icon {
margin-left: 0.5rem;
}
.button.prev, .button.next {
padding: 0.8rem;
}
.navbar .button + .button {
margin-left: 0.25rem;
}
.navbar .navbar--range {
margin-left: 1rem;
font-size: 1.25rem;
}
.navbar .nav-checkbox {
margin-left: auto;
}
input:disabled + label {
color: #ccc;
cursor: not-allowed;
}
.toastui-calendar-template-time strong {
color: inherit;
}
.sidebar-item input[type="checkbox"]:not(.checkbox-all) {
visibility: hidden;
}
.checkbox {
position: relative;
}
.checkbox-calendar::before {
content: "";
position: absolute;
left: -1.5rem;
width: 1.25rem;
height: 1.25rem;
border-radius: 50%;
border: 1px solid #ddd;
}
.checkbox.checkbox-1::before {
background-color: var(--checkbox-1);
}
.checkbox.checkbox-2::before {
background-color: var(--checkbox-2);
}
.checkbox.checkbox-3::before {
background-color: var(--checkbox-3);
}
.checkbox.checkbox-4::before {
background-color: var(--checkbox-4);
}
.checkbox.checkbox-5::before {
background-color: var(--checkbox-5);
}
================================================
FILE: apps/calendar/examples/styles/icons.css
================================================
/* font icons */
@font-face {
font-family: 'tui-calendar-font-icon';
src: url('../fonts/icon.eot') format('embedded-opentype'),
url('../fonts/icon.ttf') format('truetype'),
url('../fonts/icon.woff') format('woff'),
url('../fonts/icon.svg') format('svg');
}
.calendar-icon {
width: 14px;
height: 14px;
display: inline-block;
vertical-align: middle;
}
.calendar-font-icon {
font-family: 'tui-calendar-font-icon', sans-serif;
font-size: 10px;
font-weight: normal;
}
.img-bi {
background: url('../images/img-bi.png') no-repeat;
width: 215px;
height: 16px;
}
.ic_view_month {
background: url('../images/ic-view-month.png') no-repeat;
}
.ic_view_week {
background: url('../images/ic-view-week.png') no-repeat;
}
.ic_view_day {
background: url('../images/ic-view-day.png') no-repeat;
}
.ic-arrow-line-left {
background: url('../images/ic-arrow-line-left.png') no-repeat;
}
.ic-arrow-line-right {
background: url('../images/ic-arrow-line-right.png') no-repeat;
}
.ic-travel-time {
background: url('../images/ic-traveltime-w.png') no-repeat;
}
/* font icons */
.ic-location-b:before {
content: '\e900';
}
.ic-lock-b:before {
content: '\e901';
}
.ic-milestone-b:before {
content: '\e902';
}
.ic-readonly-b:before {
content: '\e903';
}
.ic-repeat-b:before {
content: '\e904';
}
.ic-state-b:before {
content: '\e905';
}
.ic-user-b:before {
content: '\e906';
}
================================================
FILE: apps/calendar/examples/styles/reset.css
================================================
@import url(https://fonts.googleapis.com/css?family=Noto+Sans);
*, *::before, *::after {
box-sizing: border-box;
}
* {
margin: 0;
}
html, body {
height: 100%;
}
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
font-family: 'Noto Sans', sans-serif;
}
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
input, button, textarea, select {
font: inherit;
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}
================================================
FILE: apps/calendar/jest.config.js
================================================
module.exports = {
testEnvironment: 'jsdom',
clearMocks: true,
preset: 'ts-jest',
moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'node', 'd.ts'],
moduleNameMapper: {
'\\.(css)$': '<rootDir>/src/test/cssFileMock.ts',
'^@src/(.*)$': '<rootDir>/src/$1',
'^@stories/(.*)$': '<rootDir>/stories/$1',
},
globals: { 'ts-jest': { tsconfig: '<rootDir>/tsconfig.test.json' } },
watchPathIgnorePatterns: ['<rootDir>/.storybook', '<rootDir>/.stories', '/node_modules/'],
testPathIgnorePatterns: ['/node_modules/', '/dist/', '/playwright/'],
setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts', '<rootDir>/src/test/matchers.ts'],
};
================================================
FILE: apps/calendar/jsdoc.conf.json
================================================
{
"source": {
"include": [
"src/js/factory/calendar.js",
"src/js/theme/themeConfig.js",
"src/js/common/timezone.js",
"README.md"
],
"exclude": [],
"includePattern": ".+\\.js(doc)?$",
"excludePattern": "(^|\\/|\\\\)_"
},
"plugins": [
"plugins/markdown"
],
"templates": {
"name": "Calendar",
"logo": {
"url": "https://cloud.githubusercontent.com/assets/12269563/20029815/01133928-a39a-11e6-80f3-12500a91c755.png",
"width": "150px",
"height": "13px",
"link": "https://github.com/nhn/tui.jsdoc-template"
}
},
"opts": {
"private": false,
"recurse": true,
"destination": "doc",
"tutorials": "examples",
"template": "../../node_modules/tui-jsdoc-template",
"package": "package.json"
}
}
================================================
FILE: apps/calendar/package.json
================================================
{
"name": "@toast-ui/calendar",
"author": "NHN Cloud FE Development Lab <dl_javascript@nhn.com>",
"version": "2.1.3",
"main": "./dist/toastui-calendar.js",
"types": "./types/index.d.ts",
"sideEffects": [
"*.css"
],
"module": "./dist/toastui-calendar.mjs",
"exports": {
".": {
"import": "./dist/toastui-calendar.mjs",
"require": "./dist/toastui-calendar.js"
},
"./ie11": "./dist/toastui-calendar.ie11.js",
"./esm": "./dist/toastui-calendar.mjs",
"./toastui-calendar.css": "./dist/toastui-calendar.css",
"./toastui-calendar.min.css": "./dist/toastui-calendar.min.css",
"./dist/*": "./dist/*"
},
"typesVersions": {
"*": {
"*": [
"./types/index.d.ts"
]
}
},
"license": "MIT",
"description": "TOAST UI Calendar",
"repository": {
"type": "git",
"url": "https://github.com/nhn/tui.calendar.git"
},
"keywords": [
"nhn",
"toast",
"toastui",
"toast-ui",
"calendar",
"fullcalendar",
"daily",
"weekly",
"monthly",
"business week",
"milestone",
"task",
"allday"
],
"files": [
"dist",
"types/index.d.ts",
"types/factory",
"types/time/date.d.ts",
"types/types/@(events|options|template|theme|eventBus).d.ts"
],
"dependencies": {
"immer": "^9.0.15",
"isomorphic-dompurify": "^0.20.0",
"preact": "^10.10.0",
"preact-render-to-string": "^5.2.1",
"tui-date-picker": "^4.0.1",
"tui-time-picker": "^2.0.1"
},
"devDependencies": {
"@storybook/addons": "^6.5.9",
"@storybook/builder-webpack5": "^6.5.9",
"@storybook/core": "^6.5.9",
"@storybook/manager-webpack5": "^6.5.9",
"@storybook/preact": "^6.5.9",
"@storybook/theming": "^6.5.9",
"@types/chance": "^1.1.3",
"chance": "^1.1.8",
"css-loader": "^6.7.1",
"css-minimizer-webpack-plugin": "^3.4.1",
"eslint-webpack-plugin": "^3.2.0",
"postcss": "^8.4.14",
"postcss-loader": "^6.2.1",
"postcss-prefixer": "^2.1.3",
"storybook": "^6.5.9",
"style-loader": "^3.3.1",
"stylelint": "^14.9.1",
"stylelint-config-recommended": "^8.0.0",
"stylelint-webpack-plugin": "^3.3.0",
"terser-webpack-plugin": "^5.3.3",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-inject-plugin": "^1.5.5"
},
"scripts": {
"check-types": "tsc -p ./tsconfig.json --noEmit",
"lint": "npm run check-types && eslint .",
"release-note": "tuie",
"build": "rimraf dist/ && concurrently 'npm:build:*'",
"build:modern": "webpack --config webpack.config.js && webpack --config webpack.config.js --env minify",
"build:ie11": "webpack --config webpack.config.js --env ie11 && webpack --config webpack.config.js --env minify ie11",
"build:esm": "vite build",
"build:types": "rimraf types/ && tsc -p ./tsconfig.declaration.json",
"analyze": "webpack --config webpack.config.js --env --profile --json > stats.json && webpack-bundle-analyzer stats.json ./dist",
"develop": "npm run storybook",
"storybook": "start-storybook -p 6006",
"storybook:build": "build-storybook",
"docs:prebuild": "npm run build && tsc --outDir tmpdoc --sourceMap false",
"docs:dev": "rimraf tmpdoc/ && npm run docs:prebuild && source ~/.nvm/nvm.sh && nvm use 10 && tuidoc --serv",
"docs:build": "rimraf tmpdoc/ && npm run docs:prebuild && source ~/.nvm/nvm.sh && nvm use 10 && tuidoc",
"publish:cdn": "node scripts/publishToCDN.js",
"update:wrapper": "node scripts/updateWrapper.js"
}
}
================================================
FILE: apps/calendar/playwright/assertions.ts
================================================
import type { Locator, Page } from '@playwright/test';
import { expect } from '@playwright/test';
import type { FormattedTimeString } from '@t/time/datetime';
import type { BoundingBox } from './types';
import { getBoundingBox } from './utils';
export async function assertDayGridSelectionMatching(
page: Page,
startIdx: number,
endIdx: number,
cellClassName: string,
selectionClassName: string
) {
const startCellLocator = page.locator(cellClassName).nth(startIdx);
const endCellLocator = page.locator(cellClassName).nth(endIdx);
const selectionLocator = page.locator(selectionClassName);
const selectionStartLocator = selectionLocator.first();
const selectionEndLocator = selectionLocator.last();
const [
startCellBoundingBox,
endCellBoundingBox,
selectionStartBoundingBox,
selectionEndBoundingBox,
] = await Promise.all([
getBoundingBox(startCellLocator),
getBoundingBox(endCellLocator),
getBoundingBox(selectionStartLocator),
getBoundingBox(selectionEndLocator),
]);
expect(selectionStartBoundingBox.x).toBeCloseTo(startCellBoundingBox.x, -1);
expect(selectionStartBoundingBox.y).toBeCloseTo(startCellBoundingBox.y, -1);
expect(selectionEndBoundingBox.x + selectionEndBoundingBox.width).toBeCloseTo(
endCellBoundingBox.x + endCellBoundingBox.width,
-1
);
expect(selectionEndBoundingBox.y).toBeCloseTo(endCellBoundingBox.y, -1);
const totalCellCount = endIdx - startIdx + 1;
const totalSelectionWidth = await selectionLocator.evaluateAll((selections) =>
(selections as HTMLElement[]).reduce(
(total, selectionRow) => selectionRow.getBoundingClientRect().width + total,
0
)
);
expect(Math.floor(totalSelectionWidth / totalCellCount)).toBeCloseTo(
startCellBoundingBox.width,
-1
);
}
export async function assertAccumulatedDayGridSelectionMatching(
page: Page,
startIdx: number,
endIdx: number,
nthSelection: number,
isAcrossWeeks: boolean
) {
const cellClassName = '.toastui-calendar-daygrid-cell';
const selectionClassName =
'.toastui-calendar-accumulated-grid-selection .toastui-calendar-grid-selection';
const startCellLocator = page.locator(cellClassName).nth(startIdx);
const endCellLocator = page.locator(cellClassName).nth(endIdx);
const selectionLocator = page.locator(selectionClassName);
const selectionStartLocator = selectionLocator.nth(nthSelection);
const selectionEndLocator = selectionLocator.nth(isAcrossWeeks ? nthSelection + 1 : nthSelection);
const [
startCellBoundingBox,
endCellBoundingBox,
selectionStartBoundingBox,
selectionEndBoundingBox,
] = await Promise.all([
getBoundingBox(startCellLocator),
getBoundingBox(endCellLocator),
getBoundingBox(selectionStartLocator),
getBoundingBox(selectionEndLocator),
]);
expect(selectionStartBoundingBox.x).toBeCloseTo(startCellBoundingBox.x, -1);
expect(selectionStartBoundingBox.y).toBeCloseTo(startCellBoundingBox.y, -1);
expect(selectionEndBoundingBox.x + selectionEndBoundingBox.width).toBeCloseTo(
endCellBoundingBox.x + endCellBoundingBox.width,
-1
);
expect(selectionEndBoundingBox.y).toBeCloseTo(endCellBoundingBox.y, -1);
const totalCellCount = endIdx - startIdx + 1;
const startSelectionWidth = await selectionStartLocator.evaluateAll((selections) =>
(selections as HTMLElement[]).reduce(
(total, selectionRow) => selectionRow.getBoundingClientRect().width + total,
0
)
);
const endSelectionWidth = await selectionEndLocator.evaluateAll((selections) =>
(selections as HTMLElement[]).reduce(
(total, selectionRow) => selectionRow.getBoundingClientRect().width + total,
0
)
);
const totalSelectionWidth = isAcrossWeeks
? startSelectionWidth + endSelectionWidth
: (startSelectionWidth + endSelectionWidth) / 2;
expect(Math.floor(totalSelectionWidth / totalCellCount)).toBeCloseTo(
startCellBoundingBox.width,
-1
);
}
export function assertBoundingBoxIncluded(targetBox: BoundingBox, wrappingBox: BoundingBox) {
expect(targetBox.x).toBeGreaterThanOrEqual(wrappingBox.x);
expect(targetBox.y).toBeGreaterThanOrEqual(wrappingBox.y);
expect(targetBox.x + targetBox.width).toBeLessThanOrEqual(wrappingBox.x + wrappingBox.width);
expect(targetBox.y + targetBox.height).toBeLessThanOrEqual(wrappingBox.y + wrappingBox.height);
}
export async function assertTimeGridSelection(
selectionLocator: Locator,
expected: {
startTop: number;
endBottom: number;
totalElements?: number; // not used in day view tests
formattedTimes: FormattedTimeString[];
}
) {
const timeGridSelectionElements = (await selectionLocator.evaluateAll(
(selection) => selection
)) as HTMLElement[];
const expectedFormattedTime = expected.formattedTimes.join(' - ');
if (expected.totalElements) {
expect(timeGridSelectionElements).toHaveLength(expected.totalElements);
}
await expect(selectionLocator.first()).toHaveText(expectedFormattedTime);
const firstElementBoundingBox = await getBoundingBox(selectionLocator.first());
expect(firstElementBoundingBox.y).toBeCloseTo(expected.startTop, 0);
const lastElementBoundingBox = await getBoundingBox(selectionLocator.last());
expect(lastElementBoundingBox.y + lastElementBoundingBox.height).toBeCloseTo(
expected.endBottom,
0
);
}
================================================
FILE: apps/calendar/playwright/configs.ts
================================================
const PORT = process.env.CI ? 8080 : 6006;
const generatePageUrl = (viewId: string) =>
`http://localhost:${PORT}/iframe.html?id=${viewId}&args=&viewMode=story`;
export const DAY_VIEW_PAGE_URL = generatePageUrl('e2e-day-view--fixed-events');
export const WEEK_VIEW_PAGE_URL = generatePageUrl('e2e-week-view--fixed-events');
export const WEEK_VIEW_TIMEZONE_PAGE_URL = generatePageUrl(
'e2e-week-view--different-primary-timezone'
);
export const WEEK_VIEW_DUPLICATE_EVENTS_PAGE_URL = generatePageUrl(
'e2e-week-view--duplicate-events'
);
export const WEEK_VIEW_HOUR_START_OPTION_PAGE_URL = generatePageUrl(
'e2e-week-view--hour-start-option'
);
export const MONTH_VIEW_EMPTY_PAGE_URL = generatePageUrl('e2e-month-view--empty');
export const MONTH_VIEW_PAGE_URL = generatePageUrl('e2e-month-view--fixed-events');
================================================
FILE: apps/calendar/playwright/constants.ts
================================================
export enum ClickDelay {
Immediate = 1,
Short = 100,
Long = 300,
}
================================================
FILE: apps/calendar/playwright/day/timeGridEventMoving.e2e.ts
================================================
import { expect, test } from '@playwright/test';
import type { Matchers } from '@playwright/test/types/expect-types';
import type TZDate from '../../src/time/date';
import { addHours, isSameDate, setTimeStrToDate } from '../../src/time/datetime';
import type { FormattedTimeString } from '../../src/types/time/datetime';
import { mockDayViewEvents } from '../../stories/mocks/mockDayViewEvents';
import { DAY_VIEW_PAGE_URL } from '../configs';
import {
dragAndDrop,
getBoundingBox,
getGuideTimeEventSelector,
getTimeEventSelector,
getTimeGridLineSelector,
getTimeStrFromDate,
waitForSingleElement,
} from '../utils';
test.beforeEach(async ({ page }) => {
await page.goto(DAY_VIEW_PAGE_URL);
});
const MOVE_EVENT_SELECTOR = '[class*="dragging--move-event"]';
// Every time grid events in mockDayViewEvents should include DRAG_START_TIME.
const DRAG_START_TIME = '04:00';
const cases: {
title: string;
step: number;
matcherToCompare: Extract<keyof Matchers<number>, 'toBeGreaterThan' | 'toBeLessThan'>;
}[] = [
{
title: 'to the top',
step: -3, // move to 3 hours back
matcherToCompare: 'toBeLessThan',
},
{
title: 'to the bottom',
step: 5, // move to 5 hours later
matcherToCompare: 'toBeGreaterThan',
},
];
const timeEvents = mockDayViewEvents.filter(({ isAllday }) => !isAllday);
const [, SHORT_TIME_EVENT] = timeEvents;
timeEvents.forEach(({ title: eventTitle, start, end }) => {
test.describe(`Move the ${eventTitle} event in the time grid`, () => {
cases.forEach(({ title, step }) => {
test(`${title}`, async ({ page }) => {
// Given
const targetEventSelector = `[data-testid*="time-event-${eventTitle}"]`;
const eventLocator = page.locator(targetEventSelector);
const eventBoundingBoxBeforeMove = await getBoundingBox(eventLocator);
const dragStartRowLocator = page.locator(getTimeGridLineSelector(DRAG_START_TIME));
const dragStartRowBoundingBox = await getBoundingBox(dragStartRowLocator);
const targetTime = getTimeStrFromDate(
addHours(setTimeStrToDate(end, DRAG_START_TIME), step)
) as FormattedTimeString;
const targetRowLocator = page.locator(getTimeGridLineSelector(targetTime));
const expectedStartTimeAfterMove = getTimeStrFromDate(addHours(start, step));
// When
await dragAndDrop({
page,
sourceLocator: eventLocator,
targetLocator: targetRowLocator,
options: {
sourcePosition: {
x: 1,
y: dragStartRowBoundingBox.y - eventBoundingBoxBeforeMove.y + 1,
},
targetPosition: {
y: 1,
x: 1,
},
},
});
await waitForSingleElement(eventLocator);
// Then
await expect
.poll(() => eventLocator.textContent())
.toMatch(new RegExp(expectedStartTimeAfterMove));
});
});
});
});
test('When pressing down the ESC key, the moving event resets to the initial position.', async ({
page,
}) => {
// Given
const eventLocator = page.locator(getTimeEventSelector(SHORT_TIME_EVENT.title));
const eventBoundingBoxBeforeMove = await getBoundingBox(eventLocator);
const targetStartTime = getTimeStrFromDate(
addHours(SHORT_TIME_EVENT.end as TZDate, 1)
) as FormattedTimeString;
const targetRowLocator = page.locator(getTimeGridLineSelector(targetStartTime));
// When
await dragAndDrop({
page,
sourceLocator: eventLocator,
targetLocator: targetRowLocator,
hold: true,
});
await page.keyboard.down('Escape');
// Then
const eventBoundingBoxAfterMove = await getBoundingBox(eventLocator);
expect(eventBoundingBoxAfterMove).toEqual(eventBoundingBoxBeforeMove);
});
test.describe('CSS class for a move event', () => {
test('should be applied depending on a dragging state.', async ({ page }) => {
// Given
const eventLocator = page.locator(getTimeEventSelector(SHORT_TIME_EVENT.title));
const eventBoundingBox = await getBoundingBox(eventLocator);
const moveEventClassLocator = page.locator(MOVE_EVENT_SELECTOR);
// When (a drag has not started yet)
await page.mouse.move(eventBoundingBox.x + 10, eventBoundingBox.y + 10);
await page.mouse.down();
// Then
expect(await moveEventClassLocator.count()).toBe(0);
// When (a drag is working)
await page.mouse.move(eventBoundingBox.x + 10, eventBoundingBox.y + 50);
// Then
expect(await moveEventClassLocator.count()).toBe(1);
// When (a drag is finished)
await page.mouse.up();
// Then
expect(await moveEventClassLocator.count()).toBe(0);
});
test('should not be applied when a drag is canceled.', async ({ page }) => {
// Given
const eventLocator = page.locator(getTimeEventSelector(SHORT_TIME_EVENT.title));
const moveEventClassLocator = page.locator(MOVE_EVENT_SELECTOR);
// When
await dragAndDrop({
page,
sourceLocator: eventLocator,
targetLocator: eventLocator,
options: {
targetPosition: { x: 10, y: 30 },
},
hold: true,
});
await page.keyboard.down('Escape');
// Then
expect(await moveEventClassLocator.count()).toBe(0);
});
});
const [LONG_TIME_EVENT] = mockDayViewEvents.filter(({ title }) => title === 'long time');
test.describe(`Calibrate event's height while dragging`, () => {
cases.forEach(({ title, step, matcherToCompare }) => {
test(`${title}`, async ({ page }) => {
// Given
const targetEventSelector = `[data-testid*="time-event-${LONG_TIME_EVENT.title}"]`;
const eventLocator = page.locator(targetEventSelector);
const eventBoundingBoxBeforeMove = await getBoundingBox(eventLocator);
const targetTime = getTimeStrFromDate(
addHours(setTimeStrToDate(LONG_TIME_EVENT.end, DRAG_START_TIME), step)
) as FormattedTimeString;
const targetRowLocator = page.locator(getTimeGridLineSelector(targetTime));
// When
await dragAndDrop({
page,
sourceLocator: eventLocator,
targetLocator: targetRowLocator,
hold: true,
});
// Then
await expect
.poll(async () => {
const guideBoundingBox = await getBoundingBox(eventLocator.first());
return guideBoundingBox.height;
})
[matcherToCompare](eventBoundingBoxBeforeMove.height);
});
});
});
const ONE_DAY_TIME_EVENTS = mockDayViewEvents.filter(
({ isAllday, start, end }) => !isAllday && isSameDate(start, end)
);
ONE_DAY_TIME_EVENTS.forEach(({ title }) => {
test(`The height of guide element should be same as the event element. - ${title}`, async ({
page,
}) => {
// Given
const eventLocator = page.locator(getTimeEventSelector(title));
const eventBoundingBox = await getBoundingBox(eventLocator);
const targetRowLocator = page.locator(getTimeGridLineSelector('02:00'));
// When
await dragAndDrop({
page,
sourceLocator: eventLocator,
targetLocator: targetRowLocator,
options: {
sourcePosition: {
x: 5,
y: 5,
},
targetPosition: {
y: 5,
x: 5,
},
},
hold: true,
});
// Then
const guideLocator = page.locator(getGuideTimeEventSelector());
const guideBoundingBox = await getBoundingBox(guideLocator);
expect(guideBoundingBox.height).toBeCloseTo(eventBoundingBox.height, 0);
});
});
================================================
FILE: apps/calendar/playwright/day/timeGridEventResizing.e2e.ts
================================================
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import type { Matchers } from '@playwright/test/types/expect-types';
import type TZDate from '../../src/time/date';
import { addHours, addMinutes } from '../../src/time/datetime';
import type { FormattedTimeString } from '../../src/types/time/datetime';
import { mockDayViewEvents } from '../../stories/mocks/mockDayViewEvents';
import { DAY_VIEW_PAGE_URL } from '../configs';
import {
dragAndDrop,
getBoundingBox,
getTimeEventSelector,
getTimeGridLineSelector,
getTimeStrFromDate,
waitForSingleElement,
} from '../utils';
test.beforeEach(async ({ page }) => {
await page.goto(DAY_VIEW_PAGE_URL);
});
const RESIZE_HANDLER_SELECTOR = '[class*="resize-handler"]';
const RESIZE_EVENT_SELECTOR = '[class*="dragging--resize-vertical-event"]';
const cases: {
title: string;
step: number;
matcherToCompare: Extract<keyof Matchers<number>, 'toBeGreaterThan' | 'toBeLessThan'>;
}[] = [
{
title: 'to the top',
step: -1, // move the end time to 1 hour back
matcherToCompare: 'toBeLessThan',
},
{
title: 'to the bottom',
step: 2, // move the end time to 2 hours later
matcherToCompare: 'toBeGreaterThan',
},
];
async function setup({
page,
targetEventTitle,
targetEndTime,
}: {
page: Page;
targetEventTitle: string;
targetEndTime: FormattedTimeString;
}) {
// Given
const targetEventSelector = `[data-testid*="time-event-${targetEventTitle}"]`;
const eventLocator = page.locator(targetEventSelector);
const eventBoundingBoxBeforeResize = await getBoundingBox(eventLocator);
const resizeHandlerLocator = eventLocator.locator(RESIZE_HANDLER_SELECTOR);
const targetRowLocator = page.locator(getTimeGridLineSelector(targetEndTime));
const targetRowBoundingBox = await getBoundingBox(targetRowLocator);
// When
await dragAndDrop({
page,
sourceLocator: resizeHandlerLocator,
targetLocator: targetRowLocator,
options: {
sourcePosition: {
x: 1,
y: 1,
},
targetPosition: {
x: 1,
y: targetRowBoundingBox.height / 2,
},
},
});
await waitForSingleElement(eventLocator);
const eventBoundingBoxAfterResize = await getBoundingBox(eventLocator);
return {
eventLocator,
eventBoundingBoxBeforeResize,
eventBoundingBoxAfterResize,
targetRowBoundingBox,
};
}
const timeEvents = mockDayViewEvents.filter(
({ isAllday, goingDuration, comingDuration }) => !isAllday && !goingDuration && !comingDuration
);
const [, SHORT_TIME_EVENT] = timeEvents;
timeEvents.forEach(({ title: eventTitle, start, end }) => {
test.describe(`Resize the ${eventTitle} event in the time grid`, () => {
cases.forEach(({ title, step, matcherToCompare: compareAssertion }) => {
test(`${title}`, async ({ page }) => {
const targetEndTime = getTimeStrFromDate(
addMinutes(end, (step * 2 - 1) * 30)
) as FormattedTimeString;
const {
eventLocator,
eventBoundingBoxBeforeResize,
eventBoundingBoxAfterResize,
targetRowBoundingBox,
} = await setup({
page,
targetEventTitle: eventTitle,
targetEndTime,
});
// Then
expect(eventBoundingBoxAfterResize.height)[compareAssertion](
eventBoundingBoxBeforeResize.height
);
await expect.poll(() => eventLocator.textContent()).toContain(getTimeStrFromDate(start));
expect(
eventBoundingBoxAfterResize.height - eventBoundingBoxBeforeResize.height
).toBeCloseTo(targetRowBoundingBox.height * step * 2, -1);
});
});
test(`then it should have a minimum height(=1 row) even if the event is resized to before the start time`, async ({
page,
}) => {
const { eventBoundingBoxAfterResize, targetRowBoundingBox } = await setup({
page,
targetEventTitle: eventTitle,
targetEndTime: '00:00',
});
// Then
expect(eventBoundingBoxAfterResize.height).toBeCloseTo(targetRowBoundingBox.height, -1);
});
});
});
test('When pressing down the ESC key, the resizing event resets to the initial size.', async ({
page,
}) => {
// Given
const eventLocator = page.locator(getTimeEventSelector(SHORT_TIME_EVENT.title));
const eventBoundingBoxBeforeResize = await getBoundingBox(eventLocator);
const resizeHandlerLocator = eventLocator.locator(RESIZE_HANDLER_SELECTOR);
const targetStartTime = getTimeStrFromDate(
addHours(SHORT_TIME_EVENT.end as TZDate, 1)
) as FormattedTimeString;
const targetRowLocator = page.locator(getTimeGridLineSelector(targetStartTime));
// When
await dragAndDrop({
page,
sourceLocator: resizeHandlerLocator,
targetLocator: targetRowLocator,
hold: true,
});
await page.keyboard.down('Escape');
// Then
const eventBoundingBoxAfterResize = await getBoundingBox(eventLocator);
expect(eventBoundingBoxAfterResize).toEqual(eventBoundingBoxBeforeResize);
});
test.describe('CSS class for a resize event', () => {
test('should be applied depending on a dragging state.', async ({ page }) => {
// Given
const eventLocator = page.locator(getTimeEventSelector(SHORT_TIME_EVENT.title));
const resizeHandlerLocator = eventLocator.locator(RESIZE_HANDLER_SELECTOR);
const resizeHandlerBoundingBox = await getBoundingBox(resizeHandlerLocator);
const resizeEventClassLocator = page.locator(RESIZE_EVENT_SELECTOR);
// When (a drag has not started yet)
await page.mouse.move(resizeHandlerBoundingBox.x + 10, resizeHandlerBoundingBox.y + 3);
await page.mouse.down();
// Then
expect(await resizeEventClassLocator.count()).toBe(0);
// When (a drag is working)
await page.mouse.move(resizeHandlerBoundingBox.x + 10, resizeHandlerBoundingBox.y + 50);
// Then
expect(await resizeEventClassLocator.count()).toBe(1);
// When (a drag is finished)
await page.mouse.up();
// Then
expect(await resizeEventClassLocator.count()).toBe(0);
});
test('should not be applied when a drag is canceled.', async ({ page }) => {
// Given
const eventLocator = page.locator(getTimeEventSelector(SHORT_TIME_EVENT.title));
const resizeHandlerLocator = eventLocator.locator(RESIZE_HANDLER_SELECTOR);
const resizeEventClassLocator = page.locator(RESIZE_EVENT_SELECTOR);
// When
await dragAndDrop({
page,
sourceLocator: resizeHandlerLocator,
targetLocator: resizeHandlerLocator,
options: {
targetPosition: { x: 10, y: 30 },
},
hold: true,
});
await page.keyboard.down('Escape');
// Then
expect(await resizeEventClassLocator.count()).toBe(0);
});
});
================================================
FILE: apps/calendar/playwright/day/timeGridScrollSync.e2e.ts
================================================
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { mockDayViewEvents } from '../../stories/mocks/mockDayViewEvents';
import { DAY_VIEW_PAGE_URL } from '../configs';
import { getBoundingBox, getPrefixedClassName } from '../utils';
test.beforeEach(async ({ page }) => {
await page.goto(DAY_VIEW_PAGE_URL);
});
// NOTE: Syncing scroll only happens when the mousemove event is fired
// and cannot use `dragAndDrop` because it's better to be manually controlled.
function getScrollTop(el: HTMLElement) {
return el.scrollTop;
}
test.describe('Scroll syncing in time grid when selecting grid', () => {
/**
* Top right of the column should be empty
*/
async function setup(page: Page) {
const timeGridContainerLocator = page.locator(
`${getPrefixedClassName('panel')}${getPrefixedClassName('time')}`
);
const targetColumnLocator = page.locator('[data-testid*=timegrid-column]');
const containerBoundingBox = await getBoundingBox(timeGridContainerLocator);
const columnBoundingBox = await getBoundingBox(targetColumnLocator);
return {
targetColumnLocator,
timeGridContainerLocator,
containerBoundingBox,
columnBoundingBox,
};
}
test('it should sync scroll while dragging down to the bottom', async ({ page }) => {
// Given
const {
targetColumnLocator,
columnBoundingBox,
timeGridContainerLocator,
containerBoundingBox,
} = await setup(page);
const scrollTopBeforeSync = await timeGridContainerLocator.evaluate(getScrollTop);
// When
await targetColumnLocator.hover({
position: {
x: columnBoundingBox.width - 10,
y: 10,
},
force: true,
});
await page.mouse.down();
await page.mouse.move(
columnBoundingBox.x + columnBoundingBox.width / 2,
containerBoundingBox.y + containerBoundingBox.height - 10
);
// Then
await expect
.poll(async () => {
const scrollTopAfterSync = await timeGridContainerLocator.evaluate(getScrollTop);
return scrollTopAfterSync;
})
.toBeGreaterThan(scrollTopBeforeSync);
});
test('it should sync scroll while dragging up to the top', async ({ page }) => {
// Given
const {
targetColumnLocator,
columnBoundingBox,
timeGridContainerLocator,
containerBoundingBox,
} = await setup(page);
// Middle of the column
const xPosition = columnBoundingBox.x + columnBoundingBox.width / 2;
// Scroll down to the bottom of the column
await targetColumnLocator.hover();
await page.mouse.wheel(0, containerBoundingBox.height);
let scrollTopBeforeSync = await timeGridContainerLocator.evaluate(getScrollTop);
await expect
.poll(async () => {
scrollTopBeforeSync = await timeGridContainerLocator.evaluate(getScrollTop);
return scrollTopBeforeSync;
})
.toBeCloseTo(containerBoundingBox.height, -2);
// When
// drag up to the top of the column
await page.mouse.move(xPosition, containerBoundingBox.y + containerBoundingBox.height - 10);
await page.mouse.down();
await expect
.poll(async () => {
await page.mouse.move(xPosition, containerBoundingBox.y);
// Then
const scrollTopAfterSync = await timeGridContainerLocator.evaluate(getScrollTop);
return scrollTopAfterSync;
})
.toBeLessThan(scrollTopBeforeSync);
});
});
mockDayViewEvents
.filter(({ isAllday }) => !isAllday)
.forEach(({ title: eventTitle }) => {
test.describe(`Scroll syncing in time grid when moving the ${eventTitle} event`, () => {
async function setup(page: Page) {
const timeGridContainerLocator = page.locator(
`${getPrefixedClassName('panel')}${getPrefixedClassName('time')}`
);
const targetEventLocator = page.locator(`[data-testid*="time-event-${eventTitle}"]`);
const containerBoundingBox = await getBoundingBox(timeGridContainerLocator);
const eventBoundingBox = await getBoundingBox(targetEventLocator);
return {
timeGridContainerLocator,
targetEventLocator,
containerBoundingBox,
eventBoundingBox,
};
}
test('it should sync scroll while moving event to the edge of the bottom', async ({
page,
}) => {
// Given
const {
timeGridContainerLocator,
targetEventLocator,
containerBoundingBox,
eventBoundingBox,
} = await setup(page);
const scrollTopBeforeSync = await timeGridContainerLocator.evaluate(getScrollTop);
// When
await targetEventLocator.hover({
position: {
x: eventBoundingBox.width / 2,
y: 3,
},
force: true,
});
await page.mouse.down();
await page.mouse.move(
eventBoundingBox.x + eventBoundingBox.width / 2,
containerBoundingBox.y + containerBoundingBox.height - 10
);
await page.mouse.up();
// Then
await expect
.poll(async () => {
const scrollTopAfterSync = await timeGridContainerLocator.evaluate(getScrollTop);
return scrollTopAfterSync;
})
.toBeGreaterThan(scrollTopBeforeSync);
});
test('it should sync scroll while moving event to the edge of the top', async ({ page }) => {
// Given
const {
timeGridContainerLocator,
targetEventLocator,
containerBoundingBox,
eventBoundingBox,
} = await setup(page);
// Let's move the event to the bottom first.
const middleXOfEvent = eventBoundingBox.x + eventBoundingBox.width / 2;
await targetEventLocator.hover({
position: {
x: eventBoundingBox.width / 2,
y: 3,
},
force: true,
});
await page.mouse.down();
await page.mouse.move(
middleXOfEvent,
containerBoundingBox.y + containerBoundingBox.height - 10
);
await page.mouse.up();
// Then scroll down a little.
await page.mouse.wheel(0, containerBoundingBox.height / 2);
let scrollTopBeforeSync = await timeGridContainerLocator.evaluate(getScrollTop);
await expect
.poll(async () => {
scrollTopBeforeSync = await timeGridContainerLocator.evaluate(getScrollTop);
return scrollTopBeforeSync;
})
.toBeGreaterThan(containerBoundingBox.height / 2);
// When
await targetEventLocator.hover({
position: {
x: eventBoundingBox.width / 2,
y: 3,
},
force: true,
});
await page.mouse.down();
await expect
.poll(async () => {
await page.mouse.move(middleXOfEvent, containerBoundingBox.y);
// Then
const scrollTopAfterSync = await timeGridContainerLocator.evaluate(getScrollTop);
return scrollTopAfterSync;
})
.toBeLessThan(scrollTopBeforeSync);
});
});
});
================================================
FILE: apps/calendar/playwright/day/timeGridSelection.e2e.ts
================================================
import { expect, test } from '@playwright/test';
import { assertTimeGridSelection } from '../assertions';
import { DAY_VIEW_PAGE_URL } from '../configs';
import { ClickDelay } from '../constants';
import {
dragAndDrop,
getBoundingBox,
getTimeGridLineSelector,
waitForSingleElement,
} from '../utils';
test.beforeEach(async ({ page }) => {
await page.goto(DAY_VIEW_PAGE_URL);
});
const GRID_SELECTION_SELECTOR = '[data-testid*="time-grid-selection"]';
// NOTE: Only firefox automatically scrolls into view at some random tests, so narrowing the range of movement.
// Maybe `scrollIntoViewIfNeeded` is not supported in the firefox?
// reference: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoViewIfNeeded
test.describe('TimeGrid Selection', () => {
const SELECT_START_TIME = '03:00';
test('should be able to select a time slot with clicking', async ({ page }) => {
// Given
const startGridLineLocator = page.locator(getTimeGridLineSelector(SELECT_START_TIME));
const timeGridSelectionLocator = page.locator(GRID_SELECTION_SELECTOR);
const startGridLineBoundingBox = await getBoundingBox(startGridLineLocator);
// When
await startGridLineLocator.click({ force: true, delay: ClickDelay.Long });
await waitForSingleElement(timeGridSelectionLocator); // Test for debounced click handler.
// Then
await assertTimeGridSelection(timeGridSelectionLocator, {
startTop: startGridLineBoundingBox.y,
endBottom: startGridLineBoundingBox.y + startGridLineBoundingBox.height,
formattedTimes: ['03:00', '03:30'],
});
});
test.fixme('should be able to select a time slot with double clicking', async ({ page }) => {
// Given
const startGridLineLocator = page.locator(getTimeGridLineSelector(SELECT_START_TIME));
const timeGridSelectionLocator = page.locator(GRID_SELECTION_SELECTOR);
const startGridLineBoundingBox = await getBoundingBox(startGridLineLocator);
// When
await startGridLineLocator.dblclick({ force: true, delay: ClickDelay.Immediate });
// Then
await assertTimeGridSelection(timeGridSelectionLocator, {
startTop: startGridLineBoundingBox.y,
endBottom: startGridLineBoundingBox.y + startGridLineBoundingBox.height,
formattedTimes: ['03:00', '03:30'],
});
});
test('should be able to select a range of time from top to bottom', async ({ page }) => {
// Given
const startGridLineLocator = page.locator(getTimeGridLineSelector(SELECT_START_TIME));
const targetGridLineLocator = page.locator(getTimeGridLineSelector('05:00'));
const timeGridSelectionLocator = page.locator(GRID_SELECTION_SELECTOR);
const startGridLineBoundingBox = await getBoundingBox(startGridLineLocator);
const targetGridLineBoundingBox = await getBoundingBox(targetGridLineLocator);
// When
await dragAndDrop({
page,
sourceLocator: startGridLineLocator,
targetLocator: targetGridLineLocator,
});
// Then
await assertTimeGridSelection(timeGridSelectionLocator, {
formattedTimes: ['03:00', '05:30'],
startTop: startGridLineBoundingBox.y,
endBottom: targetGridLineBoundingBox.y + targetGridLineBoundingBox.height,
});
});
test('should be able to select a range of time from bottom to top', async ({ page }) => {
// Given
const startGridLineLocator = page.locator(getTimeGridLineSelector(SELECT_START_TIME));
const targetGridLineLocator = page.locator(getTimeGridLineSelector('01:00'));
const timeGridSelectionLocator = page.locator(GRID_SELECTION_SELECTOR);
const startGridLineBoundingBox = await getBoundingBox(startGridLineLocator);
const targetGridLineBoundingBox = await getBoundingBox(targetGridLineLocator);
// When
await dragAndDrop({
page,
sourceLocator: startGridLineLocator,
targetLocator: targetGridLineLocator,
});
// Then
await assertTimeGridSelection(timeGridSelectionLocator, {
formattedTimes: ['01:00', '03:30'],
startTop: targetGridLineBoundingBox.y,
endBottom: startGridLineBoundingBox.y + startGridLineBoundingBox.height,
});
});
});
test('When pressing down the ESC key, the grid selection is canceled.', async ({ page }) => {
// Given
const startGridLineLocator = page.locator(getTimeGridLineSelector('03:00'));
const targetGridLineLocator = page.locator(getTimeGridLineSelector('05:00'));
// When
await dragAndDrop({
page,
sourceLocator: startGridLineLocator,
targetLocator: targetGridLineLocator,
hold: true,
});
await page.keyboard.down('Escape');
// Then
const gridSelectionLocator = page.locator(GRID_SELECTION_SELECTOR);
expect(await gridSelectionLocator.count()).toBe(0);
});
================================================
FILE: apps/calendar/playwright/month/accumulatedGridSelection.e2e.ts
================================================
import { test } from '@playwright/test';
import { assertAccumulatedDayGridSelectionMatching } from '../assertions';
import { MONTH_VIEW_EMPTY_PAGE_URL } from '../configs';
import { selectMonthGridCells } from '../utils';
test.beforeEach(async ({ page }) => {
await page.goto(MONTH_VIEW_EMPTY_PAGE_URL);
});
test('select 2 cells in each week', async ({ page }) => {
await selectMonthGridCells(page, 21, 23);
await selectMonthGridCells(page, 28, 30);
await assertAccumulatedDayGridSelectionMatching(page, 21, 23, 0, false);
});
test('select 2 cells across 2 weeks', async ({ page }) => {
await selectMonthGridCells(page, 13, 14);
await selectMonthGridCells(page, 20, 21);
await assertAccumulatedDayGridSelectionMatching(page, 13, 14, 0, true);
});
test('select cell across 2 weeks and select cell in 1 week', async ({ page }) => {
await selectMonthGridCells(page, 13, 14);
await selectMonthGridCells(page, 24, 25);
await assertAccumulatedDayGridSelectionMatching(page, 13, 14, 0, true);
});
================================================
FILE: apps/calendar/playwright/month/eventMoving.e2e.ts
================================================
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import type { EventObject } from '../../src/types/events';
import { mockMonthViewEventsFixed } from '../../stories/mocks/mockMonthViewEvents';
import { MONTH_VIEW_PAGE_URL } from '../configs';
import { Direction } from '../types';
import {
dragAndDrop,
getBoundingBox,
getCellSelector,
getHorizontalEventSelector,
waitForSingleElement,
} from '../utils';
test.beforeEach(async ({ page }) => {
await page.goto(MONTH_VIEW_PAGE_URL);
});
const MOVE_EVENT_SELECTOR = '[class*="dragging--move-event"]';
const [TARGET_EVENT1, TARGET_EVENT2, TARGET_EVENT3] = mockMonthViewEventsFixed;
const testCases: {
event: EventObject;
startCellIndex: number;
endCellIndex: number;
directions: Direction[];
}[] = [
{
event: TARGET_EVENT1,
startCellIndex: 7,
endCellIndex: 16,
directions: [Direction.Up, Direction.Right, Direction.Down],
},
{
event: TARGET_EVENT2,
startCellIndex: 16,
endCellIndex: 18,
directions: [Direction.Up, Direction.Right, Direction.Down, Direction.Left],
},
{
event: TARGET_EVENT3,
startCellIndex: 25,
endCellIndex: 27,
directions: [Direction.Up, Direction.Right, Direction.Down, Direction.Left],
},
];
const rightDirectionTestCases = testCases.filter((testCase) =>
testCase.directions.includes(Direction.Right)
);
const leftDirectionTestCases = testCases.filter((testCase) =>
testCase.directions.includes(Direction.Left)
);
const lowerDirectionTestCases = testCases.filter((testCase) =>
testCase.directions.includes(Direction.Down)
);
const upperDirectionTestCases = testCases.filter((testCase) =>
testCase.directions.includes(Direction.Up)
);
async function setup(page: Page, event: EventObject, targetCellIndex: number) {
const targetCellLocator = page.locator(getCellSelector(targetCellIndex));
const targetCellBoundingBox = await getBoundingBox(targetCellLocator);
const eventLocator = page.locator(getHorizontalEventSelector(event)).first();
const boundingBoxBeforeMoving = await getBoundingBox(eventLocator);
await dragAndDrop({ page, sourceLocator: eventLocator, targetLocator: targetCellLocator });
await waitForSingleElement(eventLocator);
let boundingBoxAfterMoving = await getBoundingBox(eventLocator);
await expect
.poll(async () => {
boundingBoxAfterMoving = await getBoundingBox(eventLocator);
return boundingBoxAfterMoving;
})
.not.toEqual(boundingBoxBeforeMoving);
return {
targetCellBoundingBox,
boundingBoxBeforeMoving,
boundingBoxAfterMoving,
};
}
test.describe('event moving', () => {
/**
* Suppose we have the following cells in the month view.
* Each number represents the index of the cell.
*
* [
* [ 0, 1, 2, 3, 4, 5, 6],
* [ 7, 8, 9, 10, 11, 12, 13],
* [14, 15, 16, 17, 18, 19 ,20],
* [21, 22, 23, 24, 25, 26, 27],
* [28, 29, 30, 31, 32, 33, 34],
* ]
*/
rightDirectionTestCases.forEach(({ event, startCellIndex }) => {
const getRightCellIndex = (cellIndex: number) => cellIndex + 1;
test(`moving month event ${event.title} for direction right`, async ({ page }) => {
// Given
const rightCellIndex = getRightCellIndex(startCellIndex);
// When
const { targetCellBoundingBox, boundingBoxBeforeMoving, boundingBoxAfterMoving } =
await setup(page, event, rightCellIndex);
// Then
expect(boundingBoxAfterMoving.x).toBeGreaterThan(boundingBoxBeforeMoving.x);
expect(boundingBoxAfterMoving.x).toBeCloseTo(targetCellBoundingBox.x, 1);
expect(boundingBoxAfterMoving.x).toBeLessThan(
targetCellBoundingBox.x + targetCellBoundingBox.width
);
});
});
leftDirectionTestCases.forEach(({ event, startCellIndex }) => {
const getLeftCellIndex = (cellIndex: number) => cellIndex - 1;
test(`moving month event ${event.title} for direction left`, async ({ page }) => {
// Given
const leftCellIndex = getLeftCellIndex(startCellIndex);
// When
const { targetCellBoundingBox, boundingBoxBeforeMoving, boundingBoxAfterMoving } =
await setup(page, event, leftCellIndex);
// Then
expect(boundingBoxAfterMoving.x).toBeLessThan(boundingBoxBeforeMoving.x);
expect(boundingBoxAfterMoving.x).toBeCloseTo(targetCellBoundingBox.x, 1);
expect(boundingBoxAfterMoving.x).toBeLessThan(
targetCellBoundingBox.x + targetCellBoundingBox.width
);
});
});
lowerDirectionTestCases.forEach(({ event, startCellIndex }) => {
const getDownCellIndex = (cellIndex: number) => cellIndex + 7;
test(`moving month event ${event.title} for direction down`, async ({ page }) => {
// Given
const downCellIndex = getDownCellIndex(startCellIndex);
// When
const { targetCellBoundingBox, boundingBoxBeforeMoving, boundingBoxAfterMoving } =
await setup(page, event, downCellIndex);
// Then
expect(boundingBoxAfterMoving.y).toBeGreaterThan(boundingBoxBeforeMoving.y);
expect(boundingBoxAfterMoving.width).toBeCloseTo(boundingBoxBeforeMoving.width);
expect(boundingBoxAfterMoving.y).toBeGreaterThan(targetCellBoundingBox.y);
expect(boundingBoxAfterMoving.y).toBeLessThan(
targetCellBoundingBox.y + targetCellBoundingBox.height
);
});
});
upperDirectionTestCases.forEach(({ event, startCellIndex }) => {
const getUpCellIndex = (cellIndex: number) => cellIndex - 7;
test(`moving month event ${event.title} for direction up`, async ({ page }) => {
// Given
const upCellIndex = getUpCellIndex(startCellIndex);
// When
const { targetCellBoundingBox, boundingBoxBeforeMoving, boundingBoxAfterMoving } =
await setup(page, event, upCellIndex);
// Then
expect(boundingBoxAfterMoving.y).toBeLessThan(boundingBoxBeforeMoving.y);
expect(boundingBoxAfterMoving.width).toBeCloseTo(boundingBoxBeforeMoving.width);
expect(boundingBoxAfterMoving.y).toBeGreaterThan(targetCellBoundingBox.y);
expect(boundingBoxAfterMoving.y).toBeLessThan(
targetCellBoundingBox.y + targetCellBoundingBox.height
);
});
});
test('moving month grid event to end of week', async ({ page }) => {
// Given
const eventLocator = page.locator(getHorizontalEventSelector(TARGET_EVENT2));
const endOfWeekCellLocator = page.locator(getCellSelector(20));
const endOfWeekCellBoundingBox = await getBoundingBox(endOfWeekCellLocator);
const secondOfWeekCellLocator = page.locator(getCellSelector(22));
const secondOfWeekCellBoundingBox = await getBoundingBox(secondOfWeekCellLocator);
// When
await dragAndDrop({ page, sourceLocator: eventLocator, targetLocator: endOfWeekCellLocator });
// Then
await expect.poll(() => eventLocator.evaluateAll((events) => events.length)).toBe(2);
const targetEventLength = await eventLocator.evaluateAll((events) =>
(events as HTMLElement[]).reduce(
(total, eventRow) => eventRow.getBoundingClientRect().width + total,
0
)
);
const firstEventLocator = eventLocator.first();
const lastEventLocator = eventLocator.last();
const firstEventBoundingBox = await getBoundingBox(firstEventLocator);
const lastEventBoundingBox = await getBoundingBox(lastEventLocator);
expect(firstEventBoundingBox.x).toBeCloseTo(endOfWeekCellBoundingBox.x, 3);
expect(lastEventBoundingBox.x).toBeLessThan(
secondOfWeekCellBoundingBox.x + secondOfWeekCellBoundingBox.width
);
expect(firstEventBoundingBox.y).toBeLessThan(secondOfWeekCellBoundingBox.y);
expect(lastEventBoundingBox.y).toBeGreaterThan(secondOfWeekCellBoundingBox.y);
expect(targetEventLength).toBeCloseTo(endOfWeekCellBoundingBox.width * 3, 1);
});
});
test('When pressing down the ESC key, the moving event resets to the initial position.', async ({
page,
}) => {
// Given
const eventLocator = page.locator(getHorizontalEventSelector(TARGET_EVENT2)).first();
const eventBoundingBoxBeforeMove = await getBoundingBox(eventLocator);
const targetCellLocator = page.locator(getCellSelector(20));
// When
await dragAndDrop({
page,
sourceLocator: eventLocator,
targetLocator: targetCellLocator,
hold: true,
});
await page.keyboard.down('Escape');
// Then
const eventBoundingBoxAfterMove = await getBoundingBox(eventLocator);
expect(eventBoundingBoxAfterMove).toEqual(eventBoundingBoxBeforeMove);
});
test.describe('CSS class for a move event', () => {
test('should be applied depending on a dragging state.', async ({ page }) => {
// Given
const eventLocator = page.locator(getHorizontalEventSelector(TARGET_EVENT2)).first();
const eventBoundingBox = await getBoundingBox(eventLocator);
const moveEventClassLocator = page.locator(MOVE_EVENT_SELECTOR);
// When (a drag has not started yet)
await page.mouse.move(eventBoundingBox.x + 10, eventBoundingBox.y + 10);
await page.mouse.down();
// Then
expect(await moveEventClassLocator.count()).toBe(0);
// When (a drag is working)
await page.mouse.move(eventBoundingBox.x + 10, eventBoundingBox.y + 50);
// Then
expect(await moveEventClassLocator.count()).toBe(1);
// When (a drag is finished)
await page.mouse.up();
// Then
expect(await moveEventClassLocator.count()).toBe(0);
});
test('should not be applied when a drag is canceled.', async ({ page }) => {
// Given
const eventLocator = page.locator(getHorizontalEventSelector(TARGET_EVENT2)).first();
const moveEventClassLocator = page.locator(MOVE_EVENT_SELECTOR);
// When
await dragAndDrop({
page,
sourceLocator: eventLocator,
targetLocator: eventLocator,
options: {
targetPosition: { x: 10, y: 30 },
},
hold: true,
});
await page.keyboard.down('Escape');
// Then
expect(await moveEventClassLocator.count()).toBe(0);
});
});
================================================
FILE: apps/calendar/playwright/month/eventResizing.e2e.ts
================================================
import type { Locator } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { mockMonthViewEventsFixed } from '../../stories/mocks/mockMonthViewEvents';
import { assertBoundingBoxIncluded } from '../assertions';
import { MONTH_VIEW_PAGE_URL } from '../configs';
import {
dragAndDrop,
getBoundingBox,
getCellSelector,
getHorizontalEventSelector,
waitForSingleElement,
} from '../utils';
test.beforeEach(async ({ page }) => {
await page.goto(MONTH_VIEW_PAGE_URL);
});
const RESIZE_EVENT_SELECTOR = '[class*="dragging--resize-horizontal-event"]';
const [TARGET_EVENT1, TARGET_EVENT2] = mockMonthViewEventsFixed;
function getResizeIconLocatorOfEvent(eventLocator: Locator) {
return eventLocator.last().locator('data-testid=horizontal-event-resize-icon');
}
test.describe('event resizing', () => {
/**
* Suppose we have the following cells in the month view.
* Each number represents the index of the cell.
*
* [
* [ 0, 1, 2, 3, 4, 5, 6],
* [ 7, 8, 9, 10, 11, 12, 13],
* [14, 15, 16, 17, 18, 19 ,20],
* [21, 22, 23, 24, 25, 26, 27],
* [28, 29, 30, 31, 32, 33, 34],
* ]
*/
// target event is rendered from #7 to #16
const RESIZE_TARGET_SELECTOR = getHorizontalEventSelector(TARGET_EVENT1);
test('resize event to the right in the same row', async ({ page }) => {
// Given
const eventsLocator = page.locator(RESIZE_TARGET_SELECTOR);
const resizeIconLocator = getResizeIconLocatorOfEvent(eventsLocator);
const targetCellLocator = page.locator(getCellSelector(19));
const eventBoundingBoxBeforeResizing = await getBoundingBox(eventsLocator.last());
// When
await dragAndDrop({ page, sourceLocator: resizeIconLocator, targetLocator: targetCellLocator });
// Then
await expect.poll(() => eventsLocator.count()).toBe(2);
await expect
.poll(async () => {
const eventBoundingBoxAfterResizing = await getBoundingBox(eventsLocator.last());
return eventBoundingBoxAfterResizing.width;
})
.toBeGreaterThan(eventBoundingBoxBeforeResizing.width);
const targetCellBoundingBox = await getBoundingBox(targetCellLocator);
const resizeIconBoundingBoxAfterResizing = await getBoundingBox(resizeIconLocator);
assertBoundingBoxIncluded(resizeIconBoundingBoxAfterResizing, targetCellBoundingBox);
});
test('resize event to the left in the same row', async ({ page }) => {
// Given
const eventsLocator = page.locator(RESIZE_TARGET_SELECTOR);
const resizeIconLocator = getResizeIconLocatorOfEvent(eventsLocator);
const targetCellLocator = page.locator(getCellSelector(14));
const eventBoundingBoxBeforeResizing = await getBoundingBox(eventsLocator.last());
// When
await dragAndDrop({ page, sourceLocator: resizeIconLocator, targetLocator: targetCellLocator });
// Then
await expect.poll(() => eventsLocator.count()).toBe(2);
await expect
.poll(async () => {
const eventBoundingBoxAfterResizing = await getBoundingBox(eventsLocator.last());
return eventBoundingBoxAfterResizing.width;
})
.toBeLessThan(eventBoundingBoxBeforeResizing.width);
const targetCellBoundingBox = await getBoundingBox(targetCellLocator);
const resizeIconBoundingBoxAfterResizing = await getBoundingBox(resizeIconLocator);
assertBoundingBoxIncluded(resizeIconBoundingBoxAfterResizing, targetCellBoundingBox);
});
test('resize event to the right in the next two rows', async ({ page }) => {
// Given
const eventsLocator = page.locator(RESIZE_TARGET_SELECTOR);
const resizeIconLocator = getResizeIconLocatorOfEvent(eventsLocator);
const targetCellLocator = page.locator(getCellSelector(31));
// When
await dragAndDrop({ page, sourceLocator: resizeIconLocator, targetLocator: targetCellLocator });
// Then
await expect.poll(() => eventsLocator.count()).toBe(4);
const resizeIconBoundingBoxAfterResizing = await getBoundingBox(resizeIconLocator);
const targetCellBoundingBox = await getBoundingBox(targetCellLocator);
assertBoundingBoxIncluded(resizeIconBoundingBoxAfterResizing, targetCellBoundingBox);
});
test('resize event to the left in the next two rows', async ({ page }) => {
// Given
const eventsLocator = page.locator(RESIZE_TARGET_SELECTOR);
const resizeIconLocator = getResizeIconLocatorOfEvent(eventsLocator);
const targetCellLocator = page.locator(getCellSelector(28));
// When
await dragAndDrop({ page, sourceLocator: resizeIconLocator, targetLocator: targetCellLocator });
// Then
await expect.poll(() => eventsLocator.count()).toBe(4);
const resizeIconBoundingBoxAfterResizing = await getBoundingBox(resizeIconLocator);
const targetCellBoundingBox = await getBoundingBox(targetCellLocator);
assertBoundingBoxIncluded(resizeIconBoundingBoxAfterResizing, targetCellBoundingBox);
});
test('shrink event - to the end of the first row of rendered events', async ({ page }) => {
// Given
const eventsLocator = page.locator(RESIZE_TARGET_SELECTOR);
const resizeIconLocator = getResizeIconLocatorOfEvent(eventsLocator);
const targetCellLocator = page.locator(getCellSelector(13));
// When
await dragAndDrop({ page, sourceLocator: resizeIconLocator, targetLocator: targetCellLocator });
await waitForSingleElement(eventsLocator);
// Then
const resizeIconBoundingBoxAfterResizing = await getBoundingBox(resizeIconLocator);
const targetCellBoundingBox = await getBoundingBox(targetCellLocator);
assertBoundingBoxIncluded(resizeIconBoundingBoxAfterResizing, targetCellBoundingBox);
});
test('shrink event - to take place of just one cell', async ({ page }) => {
// Given
const eventsLocator = page.locator(RESIZE_TARGET_SELECTOR);
const resizeIconLocator = getResizeIconLocatorOfEvent(eventsLocator);
const targetCellLocator = page.locator(getCellSelector(7));
// When
await dragAndDrop({ page, sourceLocator: resizeIconLocator, targetLocator: targetCellLocator });
await waitForSingleElement(eventsLocator);
// Then
const resizeIconBoundingBoxAfterResizing = await getBoundingBox(resizeIconLocator);
const targetCellBoundingBox = await getBoundingBox(targetCellLocator);
assertBoundingBoxIncluded(resizeIconBoundingBoxAfterResizing, targetCellBoundingBox);
});
test('prevent resizing when dragging to above the first row of the event or left of the first cell of the event', async ({
page,
}) => {
// Given
const eventsLocator = page.locator(RESIZE_TARGET_SELECTOR);
const resizeIconLocator = getResizeIconLocatorOfEvent(eventsLocator);
const targetCellLocator = page.locator(getCellSelector(0));
const expectedCellLocator = page.locator(getCellSelector(16));
// When
await dragAndDrop({ page, sourceLocator: resizeIconLocator, targetLocator: targetCellLocator });
// Then
await expect.poll(() => eventsLocator.count()).toBe(2);
const resizeIconBoundingBoxAfterResizing = await getBoundingBox(resizeIconLocator);
const expectedCellBoundingBox = await getBoundingBox(expectedCellLocator);
assertBoundingBoxIncluded(resizeIconBoundingBoxAfterResizing, expectedCellBoundingBox);
});
});
test('When pressing down the ESC key, the resizing event resets to the initial size.', async ({
page,
}) => {
// Given
const eventLocator = page.locator(getHorizontalEventSelector(TARGET_EVENT2));
const eventBoundingBoxBeforeResize = await getBoundingBox(eventLocator.last());
const resizeHandlerLocator = getResizeIconLocatorOfEvent(eventLocator);
const targetCellLocator = page.locator(getCellSelector(20));
// When
await dragAndDrop({
page,
sourceLocator: resizeHandlerLocator,
targetLocator: targetCellLocator,
hold: true,
});
await page.keyboard.down('Escape');
// Then
const eventBoundingBoxAfterResize = await getBoundingBox(eventLocator);
expect(eventBoundingBoxAfterResize).toEqual(eventBoundingBoxBeforeResize);
});
test.describe('CSS class for a resize event', () => {
test('should be applied depending on a dragging state.', async ({ page }) => {
// Given
const eventLocator = page.locator(getHorizontalEventSelector(TARGET_EVENT2));
const resizeHandlerLocator = getResizeIconLocatorOfEvent(eventLocator);
const resizeHandlerBoundingBox = await getBoundingBox(resizeHandlerLocator);
const resizeEventClassLocator = page.locator(RESIZE_EVENT_SELECTOR);
// When (a drag has not started yet)
await page.mouse.move(resizeHandlerBoundingBox.x + 1, resizeHandlerBoundingBox.y + 3);
await page.mouse.down();
// Then
expect(await resizeEventClassLocator.count()).toBe(0);
// When (a drag is working)
await page.mouse.move(resizeHandlerBoundingBox.x + 10, resizeHandlerBoundingBox.y + 50);
// Then
expect(await resizeEventClassLocator.count()).toBe(1);
// When (a drag is finished)
await page.mouse.up();
// Then
expect(await resizeEventClassLocator.count()).toBe(0);
});
test('should not be applied when a drag is canceled.', async ({ page }) => {
// Given
const eventLocator = page.locator(getHorizontalEventSelector(TARGET_EVENT2));
const resizeHandlerLocator = getResizeIconLocatorOfEvent(eventLocator);
const resizeEventClassLocator = page.locator(RESIZE_EVENT_SELECTOR);
// When
await dragAndDrop({
page,
sourceLocator: resizeHandlerLocator,
targetLocator: resizeHandlerLocator,
options: {
targetPosition: { x: 10, y: 30 },
},
hold: true,
});
await page.keyboard.down('Escape');
// Then
expect(await resizeEventClassLocator.count()).toBe(0);
});
});
================================================
FILE: apps/calendar/playwright/month/gridSelection.e2e.ts
================================================
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { assertDayGridSelectionMatching } from '../assertions';
import { MONTH_VIEW_PAGE_URL } from '../configs';
import { ClickDelay } from '../constants';
import { dragAndDrop, getPrefixedClassName, selectMonthGridCells } from '../utils';
test.beforeEach(async ({ page }) => {
await page.goto(MONTH_VIEW_PAGE_URL);
});
const MONTH_GRID_CELL_SELECTOR = getPrefixedClassName('daygrid-cell');
const GRID_SELECTION_SELECTOR = `${getPrefixedClassName('weekday')} > ${getPrefixedClassName(
'grid-selection'
)}`;
/**
* Suppose we have the following cells in the month view.
* Each number represents the index of the cell.
*
* [
* [ 0, 1, 2, 3, 4, 5, 6],
* [ 7, 8, 9, 10, 11, 12, 13],
* [14, 15, 16, 17, 18, 19 ,20],
* [21, 22, 23, 24, 25, 26, 27],
* [28, 29, 30, 31, 32, 33, 34],
* ]
*/
function assertMonthGridSelectionMatching(page: Page, startIndex: number, endIndex: number) {
return assertDayGridSelectionMatching(
page,
startIndex,
endIndex,
MONTH_GRID_CELL_SELECTOR,
GRID_SELECTION_SELECTOR
);
}
test('select a cell by clicking.', async ({ page }) => {
// Given
const monthGridCellLocator = page.locator(MONTH_GRID_CELL_SELECTOR).nth(31);
// When
await monthGridCellLocator.click({ delay: ClickDelay.Short });
// Then
await assertMonthGridSelectionMatching(page, 31, 31);
});
// It looks like triple click happens.
// Affected by auto clearing grid selection when form popup closed.
test.fixme('select a cell by double clicking.', async ({ page }) => {
// Given
const monthGridCellLocator = page.locator(MONTH_GRID_CELL_SELECTOR).nth(31);
// When
await monthGridCellLocator.dblclick({ delay: ClickDelay.Immediate });
// Then
await assertMonthGridSelectionMatching(page, 31, 31);
});
test('select a cell by drag and drop.', async ({ page }) => {
await selectMonthGridCells(page, 31, 31);
await assertMonthGridSelectionMatching(page, 31, 31);
});
test('select 2 cells from left to right', async ({ page }) => {
await selectMonthGridCells(page, 31, 32);
await assertMonthGridSelectionMatching(page, 31, 32);
});
test('select 2 cells from right to left(reverse)', async ({ page }) => {
await selectMonthGridCells(page, 32, 31);
await assertMonthGridSelectionMatching(page, 31, 32);
});
test('select 2 rows from top to bottom', async ({ page }) => {
await selectMonthGridCells(page, 25, 32);
await assertMonthGridSelectionMatching(page, 25, 32);
});
test('select 2 rows from bottom to top(reverse)', async ({ page }) => {
await selectMonthGridCells(page, 32, 25);
await assertMonthGridSelectionMatching(page, 25, 32);
});
test('select entire row', async ({ page }) => {
await selectMonthGridCells(page, 28, 34);
await assertMonthGridSelectionMatching(page, 28, 34);
});
test('event form popup with grid selection', async ({ page }) => {
await selectMonthGridCells(page, 28, 34);
const floatingLayer = page.locator('css=[role=dialog]');
expect(floatingLayer).not.toBeNull();
});
test('When pressing down the ESC key, the grid selection is canceled.', async ({ page }) => {
// Given
const startCellLocator = page.locator(MONTH_GRID_CELL_SELECTOR).nth(31);
const targetCellLocator = page.locator(MONTH_GRID_CELL_SELECTOR).nth(32);
// When
await dragAndDrop({
page,
sourceLocator: startCellLocator,
targetLocator: targetCellLocator,
hold: true,
});
await page.keyboard.down('Escape');
// Then
const gridSelectionLocator = page.locator(GRID_SELECTION_SELECTOR);
expect(await gridSelectionLocator.count()).toBe(0);
});
================================================
FILE: apps/calendar/playwright/month/seeMoreEventsPopup.e2e.ts
================================================
import { expect, test } from '@playwright/test';
import { MONTH_VIEW_PAGE_URL } from '../configs';
test.beforeEach(async ({ page }) => {
await page.goto(MONTH_VIEW_PAGE_URL);
});
test.describe('more events popup', () => {
test('when clicking on "more events" button, popup should be visible', async ({ page }) => {
await page.click('text=/\\d+ more/i >> nth=0');
const popupLocator = page.locator('css=[role=dialog]');
expect(await popupLocator.isVisible()).toBe(true);
const listLocator = popupLocator.locator('css=[class*=list]');
const listItemCount = await listLocator.evaluate((list) => list.children.length);
expect(listItemCount).toBeGreaterThan(0);
});
});
================================================
FILE: apps/calendar/playwright/month/visibleEventCount.e2e.ts
================================================
import { expect, test } from '@playwright/test';
import { MONTH_VIEW_PAGE_URL } from '../configs';
import { getCellSelector, getPrefixedClassName } from '../utils';
test.beforeEach(async ({ page }) => {
await page.goto(MONTH_VIEW_PAGE_URL);
});
const eventsRowClassName = getPrefixedClassName('weekday-events');
test.describe('visibleEventCount option', () => {
// In the default viewport, 3 event blocks are visible.
// 16th cell has 12 events.
test('when visibleEventCount is set to 0, no events should be visible', async ({ page }) => {
// Given
const targetCell = page.locator(getCellSelector(16));
const events = page.locator(eventsRowClassName).nth(2);
// When
await page.evaluate(() => {
window.$cal.setOptions({
month: {
visibleEventCount: 0,
},
});
});
// Then
expect(await events.evaluate((_events) => _events.children.length)).toBe(0);
const moreButton = targetCell.locator('button');
await expect(moreButton).toHaveText('12 more');
});
test('when visibleEventCount is bigger than the content area, it only shows events within the content area', async ({
page,
}) => {
// Given
const targetCell = page.locator(getCellSelector(16));
const events = page.locator(eventsRowClassName).nth(2);
// When
await page.evaluate(() => {
window.$cal.setOptions({
month: {
visibleEventCount: 10,
},
});
});
// Then
expect(await events.evaluate((_events) => _events.children.length)).toBe(3);
const moreButton = targetCell.locator('button');
await expect(moreButton).toHaveText('9 more');
});
});
================================================
FILE: apps/calendar/playwright/playwright-env.d.ts
================================================
import type Calendar from '../src/factory/calendar';
declare global {
interface Window {
$cal: Calendar;
}
}
================================================
FILE: apps/calendar/playwright/types.ts
================================================
export type BoundingBox = {
x: number;
y: number;
width: number;
height: number;
};
export enum Direction {
Up = 0,
UpperRight = 1,
Right = 2,
LowerRight = 3,
Down = 4,
LowerLeft = 5,
Left = 6,
UpperLeft = 7,
}
================================================
FILE: apps/calendar/playwright/utils.ts
================================================
import type { Locator, Page } from '@playwright/test';
import { expect } from '@playwright/test';
import type TZDate from '../src/time/date';
import type { EventObject } from '../src/types/events';
import type { FormattedTimeString } from '../src/types/time/datetime';
import type { BoundingBox } from './types';
export function getPrefixedClassName(className: string) {
return `.toastui-calendar-${className}`;
}
export async function dragAndDrop({
page,
sourceLocator,
targetLocator,
options = {},
hold = false,
}: {
page: Page;
sourceLocator: Locator;
targetLocator: Locator;
options?: Parameters<Locator['dragTo']>[1];
hold?: boolean;
}) {
const sourceBoundingBox = await getBoundingBox(sourceLocator);
const targetBoundingBox = await getBoundingBox(targetLocator);
const sourceX = sourceBoundingBox.x + (options?.sourcePosition?.x ?? sourceBoundingBox.width / 2);
const sourceY =
sourceBoundingBox.y + (options?.sourcePosition?.y ?? sourceBoundingBox.height / 2);
const targetX = targetBoundingBox.x + (options?.targetPosition?.x ?? targetBoundingBox.width / 2);
const targetY =
targetBoundingBox.y + (options?.targetPosition?.y ?? targetBoundingBox.height / 2);
await page.mouse.move(sourceX, sourceY);
await page.mouse.down();
await page.mouse.move(targetX, targetY, { steps: 4 });
if (!hold) {
await page.mouse.up();
}
}
export async function selectGridCells(
page: Page,
startCellIdx: number,
endCellIdx: number,
className: string
) {
const startCellLocator = page.locator(className).nth(startCellIdx);
const endCellLocator = page.locator(className).nth(endCellIdx);
await dragAndDrop({ page, sourceLocator: startCellLocator, targetLocator: endCellLocator });
}
export function selectMonthGridCells(page: Page, startCellIndex: number, endCellIndex: number) {
return selectGridCells(page, startCellIndex, endCellIndex, '.toastui-calendar-daygrid-cell');
}
export async function getBoundingBox(locator: Locator): Promise<BoundingBox> {
const boundingBox = await locator.boundingBox();
if (!boundingBox) {
throw new Error(`BoundingBox of ${locator} is not found`);
}
return boundingBox;
}
export function getTimeEventSelector(title: string): string {
return `[data-testid^="time-event-${title}-"]`;
}
export function getGuideTimeEventSelector(): string {
return `[data-testid^="guide-time-event"]`;
}
export function getHorizontalEventSelector(event: EventObject): string {
return `data-testid=${event.calendarId}-${event.id}-${event.title}`;
}
export function getTimeGridLineSelector(start: FormattedTimeString): string {
return `[data-testid*="gridline-${start}"]`;
}
export function getCellSelector(cellIndex: number): string {
return `.toastui-calendar-daygrid-cell >> nth=${cellIndex}`;
}
export function getTimeStrFromDate(d: TZDate) {
const fixToTwoDigits = (num: number) => num.toString().padStart(2, '0');
const hour = d.getHours();
const minute = d.getMinutes();
return `${fixToTwoDigits(hour)}:${fixToTwoDigits(minute)}`;
}
export function waitForSingleElement(locator: Locator) {
return expect.poll(() => locator.count()).toBe(1);
}
/**
* Get locator matches testId.
*/
export function queryLocatorByTestId(page: Page, testId: string) {
return page.locator(`[data-testid*="${testId}"]`);
}
================================================
FILE: apps/calendar/playwright/week/alldayGridEventMoving.e2e.ts
================================================
import type { Locator } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { mockWeekViewEvents } from '../../stories/mocks/mockWeekViewEvents';
import { WEEK_VIEW_PAGE_URL } from '../configs';
import {
dragAndDrop,
getBoundingBox,
getHorizontalEventSelector,
getPrefixedClassName,
} from '../utils';
test.beforeEach(async ({ page }) => {
await page.goto(WEEK_VIEW_PAGE_URL);
});
const ALL_DAY_GRID_CELL_SELECTOR = `${getPrefixedClassName(
'panel'
)}:has-text("All Day") ${getPrefixedClassName('panel-grid')}`;
const MOVE_EVENT_SELECTOR = '[class*="dragging--move-event"]';
const [TARGET_EVENT] = mockWeekViewEvents.filter(({ isAllday }) => isAllday);
const TARGET_EVENT_SELECTOR = getHorizontalEventSelector(TARGET_EVENT);
async function getX(locator: Locator) {
const boundingBox = await getBoundingBox(locator);
return boundingBox.x;
}
async function getWidth(locator: Locator) {
const boundingBox = await getBoundingBox(locator);
return boundingBox.width;
}
/**
* Suppose we have the following cells in the week view.
* Each number represents the index of the cell.
*
* [ 0, 1, 2, 3, 4, 5, 6]
*/
test('moving allday grid row event from left to right', async ({ page }) => {
// Given
const targetEventLocator = page.locator(TARGET_EVENT_SELECTOR);
const boundingBoxBeforeMoving = await getBoundingBox(targetEventLocator);
const fifthOfWeekCellLocator = page.locator(ALL_DAY_GRID_CELL_SELECTOR).nth(4);
// When
await dragAndDrop({
page,
sourceLocator: targetEventLocator,
targetLocator: fifthOfWeekCellLocator,
});
// Then
await expect.poll(() => getX(targetEventLocator)).toBeGreaterThan(boundingBoxBeforeMoving.x);
await expect
.poll(() => getWidth(targetEventLocator))
.toBeCloseTo(boundingBoxBe
gitextract_fijh9az9/
├── .eslintignore
├── .eslintrc.js
├── .github/
│ ├── composite-actions/
│ │ └── install-dependencies/
│ │ └── action.yml
│ └── workflows/
│ ├── publish-calendar.yml
│ ├── publish-docs.yml
│ ├── publish-wrappers.yml
│ └── test.yml
├── .gitignore
├── .husky/
│ ├── .gitignore
│ └── pre-commit
├── .prettierignore
├── .prettierrc
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── apps/
│ ├── calendar/
│ │ ├── .browserslistrc
│ │ ├── .lintstagedrc.js
│ │ ├── .storybook/
│ │ │ ├── main.js
│ │ │ ├── manager.js
│ │ │ ├── preview.js
│ │ │ └── theme.js
│ │ ├── README.md
│ │ ├── examples/
│ │ │ ├── 00-calendar-app.html
│ │ │ ├── 01-monthly-view-basic.html
│ │ │ ├── 02-monthly-view-2weeks.html
│ │ │ ├── 03-monthly-view-3weeks.html
│ │ │ ├── 04-weekly-view.html
│ │ │ ├── 05-weekly-view-no-event-view.html
│ │ │ ├── 06-daily-view.html
│ │ │ ├── 07-narrow-weekends.html
│ │ │ ├── 08-hidden-weekends.html
│ │ │ ├── 09-timezone.html
│ │ │ ├── 10-theme-common.html
│ │ │ ├── 11-theme-monthly.html
│ │ │ ├── 12-theme-weekly.html
│ │ │ ├── 13-template-monthly.html
│ │ │ ├── 14-template-weekly.html
│ │ │ ├── 15-template-popup.html
│ │ │ ├── scripts/
│ │ │ │ ├── app.js
│ │ │ │ ├── mock-data.js
│ │ │ │ └── utils.js
│ │ │ └── styles/
│ │ │ ├── app.css
│ │ │ ├── icons.css
│ │ │ └── reset.css
│ │ ├── jest.config.js
│ │ ├── jsdoc.conf.json
│ │ ├── package.json
│ │ ├── playwright/
│ │ │ ├── assertions.ts
│ │ │ ├── configs.ts
│ │ │ ├── constants.ts
│ │ │ ├── day/
│ │ │ │ ├── timeGridEventMoving.e2e.ts
│ │ │ │ ├── timeGridEventResizing.e2e.ts
│ │ │ │ ├── timeGridScrollSync.e2e.ts
│ │ │ │ └── timeGridSelection.e2e.ts
│ │ │ ├── month/
│ │ │ │ ├── accumulatedGridSelection.e2e.ts
│ │ │ │ ├── eventMoving.e2e.ts
│ │ │ │ ├── eventResizing.e2e.ts
│ │ │ │ ├── gridSelection.e2e.ts
│ │ │ │ ├── seeMoreEventsPopup.e2e.ts
│ │ │ │ └── visibleEventCount.e2e.ts
│ │ │ ├── playwright-env.d.ts
│ │ │ ├── types.ts
│ │ │ ├── utils.ts
│ │ │ └── week/
│ │ │ ├── alldayGridEventMoving.e2e.ts
│ │ │ ├── alldayGridEventResizing.e2e.ts
│ │ │ ├── dayGridSelection.e2e.ts
│ │ │ ├── hourStartOption.e2e.ts
│ │ │ ├── primaryTimezone.e2e.ts
│ │ │ ├── timeGridEventClick.e2e.ts
│ │ │ ├── timeGridEventMoving.e2e.ts
│ │ │ ├── timeGridEventResizing.e2e.ts
│ │ │ ├── timeGridScrollSync.e2e.ts
│ │ │ └── timeGridSelection.e2e.ts
│ │ ├── postcss.config.js
│ │ ├── scripts/
│ │ │ ├── publishToCDN.js
│ │ │ └── updateWrapper.js
│ │ ├── src/
│ │ │ ├── calendarContainer.tsx
│ │ │ ├── components/
│ │ │ │ ├── dayGridCommon/
│ │ │ │ │ ├── dayName.tsx
│ │ │ │ │ ├── gridHeader.tsx
│ │ │ │ │ └── gridSelection.tsx
│ │ │ │ ├── dayGridMonth/
│ │ │ │ │ ├── accumulatedGridSelection.tsx
│ │ │ │ │ ├── cellHeader.tsx
│ │ │ │ │ ├── dayGridMonth.tsx
│ │ │ │ │ ├── gridCell.tsx
│ │ │ │ │ ├── gridRow.tsx
│ │ │ │ │ ├── gridSelectionByRow.tsx
│ │ │ │ │ ├── monthEvents.tsx
│ │ │ │ │ ├── moreEventsButton.tsx
│ │ │ │ │ ├── movingEventShadow.tsx
│ │ │ │ │ └── resizingGuideByRow.tsx
│ │ │ │ ├── dayGridWeek/
│ │ │ │ │ ├── alldayGridRow.tsx
│ │ │ │ │ ├── alldayGridSelection.tsx
│ │ │ │ │ ├── gridCell.tsx
│ │ │ │ │ ├── gridCells.tsx
│ │ │ │ │ ├── movingEventShadow.tsx
│ │ │ │ │ ├── otherGridRow.tsx
│ │ │ │ │ └── resizingEventShadow.tsx
│ │ │ │ ├── events/
│ │ │ │ │ ├── backgroundEvent.tsx
│ │ │ │ │ ├── horizontalEvent.spec.tsx
│ │ │ │ │ ├── horizontalEvent.tsx
│ │ │ │ │ ├── horizontalEventResizeIcon.tsx
│ │ │ │ │ ├── timeEvent.spec.tsx
│ │ │ │ │ └── timeEvent.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ ├── panel.tsx
│ │ │ │ ├── panelResizer.tsx
│ │ │ │ ├── popup/
│ │ │ │ │ ├── calendarDropdownMenu.tsx
│ │ │ │ │ ├── calendarSelector.tsx
│ │ │ │ │ ├── closePopupButton.tsx
│ │ │ │ │ ├── confirmPopupButton.tsx
│ │ │ │ │ ├── dateSelector.tsx
│ │ │ │ │ ├── eventDetailPopup.spec.tsx
│ │ │ │ │ ├── eventDetailPopup.tsx
│ │ │ │ │ ├── eventDetailSectionDetail.tsx
│ │ │ │ │ ├── eventDetailSectionHeader.tsx
│ │ │ │ │ ├── eventFormPopup.spec.tsx
│ │ │ │ │ ├── eventFormPopup.tsx
│ │ │ │ │ ├── eventStateSelector.tsx
│ │ │ │ │ ├── locationInputBox.tsx
│ │ │ │ │ ├── popupOverlay.tsx
│ │ │ │ │ ├── popupSection.tsx
│ │ │ │ │ ├── seeMoreEventsPopup.tsx
│ │ │ │ │ ├── stateDropdownMenu.tsx
│ │ │ │ │ └── titleInputBox.tsx
│ │ │ │ ├── template.tsx
│ │ │ │ ├── timeGrid/
│ │ │ │ │ ├── column.tsx
│ │ │ │ │ ├── gridLines.tsx
│ │ │ │ │ ├── gridSelectionByColumn.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── movingEventShadow.tsx
│ │ │ │ │ ├── nowIndicator.tsx
│ │ │ │ │ ├── nowIndicatorLabel.tsx
│ │ │ │ │ ├── resizingGuideByColumn.tsx
│ │ │ │ │ ├── timeColumn.tsx
│ │ │ │ │ ├── timeGrid.spec.tsx
│ │ │ │ │ ├── timeGrid.tsx
│ │ │ │ │ ├── timezoneCollapseButton.tsx
│ │ │ │ │ ├── timezoneCollpaseButton.spec.tsx
│ │ │ │ │ └── timezoneLabels.tsx
│ │ │ │ └── view/
│ │ │ │ ├── day.spec.tsx
│ │ │ │ ├── day.tsx
│ │ │ │ ├── main.tsx
│ │ │ │ ├── month.spec.tsx
│ │ │ │ ├── month.tsx
│ │ │ │ ├── week.spec.tsx
│ │ │ │ └── week.tsx
│ │ │ ├── constants/
│ │ │ │ ├── error.ts
│ │ │ │ ├── grid.ts
│ │ │ │ ├── keyboard.ts
│ │ │ │ ├── layout.ts
│ │ │ │ ├── message.ts
│ │ │ │ ├── mouse.ts
│ │ │ │ ├── popup.ts
│ │ │ │ ├── statistics.ts
│ │ │ │ ├── style.ts
│ │ │ │ ├── theme.ts
│ │ │ │ └── view.ts
│ │ │ ├── contexts/
│ │ │ │ ├── calendarStore.ts
│ │ │ │ ├── eventBus.spec.tsx
│ │ │ │ ├── eventBus.tsx
│ │ │ │ ├── floatingLayer.tsx
│ │ │ │ ├── layoutContainer.tsx
│ │ │ │ └── themeStore.tsx
│ │ │ ├── controller/
│ │ │ │ ├── base.spec.ts
│ │ │ │ ├── base.ts
│ │ │ │ ├── column.spec.ts
│ │ │ │ ├── column.ts
│ │ │ │ ├── core.spec.ts
│ │ │ │ ├── core.ts
│ │ │ │ ├── month.spec.ts
│ │ │ │ ├── month.ts
│ │ │ │ ├── times.spec.ts
│ │ │ │ ├── times.ts
│ │ │ │ ├── week.spec.ts
│ │ │ │ └── week.ts
│ │ │ ├── css/
│ │ │ │ ├── common.css
│ │ │ │ ├── daygrid/
│ │ │ │ │ ├── dayGrid.css
│ │ │ │ │ ├── dayNames.css
│ │ │ │ │ └── index.css
│ │ │ │ ├── events/
│ │ │ │ │ ├── background.css
│ │ │ │ │ ├── grid.css
│ │ │ │ │ ├── index.css
│ │ │ │ │ └── time.css
│ │ │ │ ├── icons.css
│ │ │ │ ├── index.css
│ │ │ │ ├── layout.css
│ │ │ │ ├── panel/
│ │ │ │ │ ├── allday.css
│ │ │ │ │ └── index.css
│ │ │ │ ├── popup/
│ │ │ │ │ ├── common.css
│ │ │ │ │ ├── detail.css
│ │ │ │ │ ├── form.css
│ │ │ │ │ ├── index.css
│ │ │ │ │ └── seeMore.css
│ │ │ │ └── timegrid/
│ │ │ │ ├── column.css
│ │ │ │ ├── index.css
│ │ │ │ ├── timeColumn.css
│ │ │ │ └── timegrid.css
│ │ │ ├── factory/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── calendarCore.spec.tsx.snap
│ │ │ │ ├── calendar.tsx
│ │ │ │ ├── calendarCore.spec.tsx
│ │ │ │ ├── calendarCore.tsx
│ │ │ │ ├── day.tsx
│ │ │ │ ├── month.spec.tsx
│ │ │ │ ├── month.tsx
│ │ │ │ ├── week.spec.tsx
│ │ │ │ └── week.tsx
│ │ │ ├── helpers/
│ │ │ │ ├── css.spec.ts
│ │ │ │ ├── css.ts
│ │ │ │ ├── dayName.ts
│ │ │ │ ├── drag.ts
│ │ │ │ ├── events.spec.ts
│ │ │ │ ├── events.ts
│ │ │ │ ├── grid.spec.ts
│ │ │ │ ├── grid.ts
│ │ │ │ ├── gridSelection.ts
│ │ │ │ ├── popup.ts
│ │ │ │ └── view.ts
│ │ │ ├── hooks/
│ │ │ │ ├── calendar/
│ │ │ │ │ ├── useCalendarById.ts
│ │ │ │ │ ├── useCalendarColor.ts
│ │ │ │ │ └── useCalendarData.ts
│ │ │ │ ├── common/
│ │ │ │ │ ├── useClickPrevention.spec.tsx
│ │ │ │ │ ├── useClickPrevention.ts
│ │ │ │ │ ├── useDOMNode.ts
│ │ │ │ │ ├── useDrag.spec.tsx
│ │ │ │ │ ├── useDrag.ts
│ │ │ │ │ ├── useDropdownState.ts
│ │ │ │ │ ├── useInterval.spec.ts
│ │ │ │ │ ├── useInterval.ts
│ │ │ │ │ ├── useIsMounted.spec.ts
│ │ │ │ │ ├── useIsMounted.ts
│ │ │ │ │ ├── useKeydownEvent.ts
│ │ │ │ │ ├── useTransientUpdate.ts
│ │ │ │ │ └── useWhen.ts
│ │ │ │ ├── dayGridMonth/
│ │ │ │ │ ├── useDayGridMonthEventMove.ts
│ │ │ │ │ └── useDayGridMonthEventResize.ts
│ │ │ │ ├── dayGridWeek/
│ │ │ │ │ ├── useAlldayGridRowEventMove.ts
│ │ │ │ │ ├── useAlldayGridRowEventResize.ts
│ │ │ │ │ └── useGridRowHeightController.ts
│ │ │ │ ├── event/
│ │ │ │ │ ├── useCurrentPointerPositionInGrid.ts
│ │ │ │ │ └── useDraggingEvent.ts
│ │ │ │ ├── gridSelection/
│ │ │ │ │ ├── useGridSelection.spec.tsx
│ │ │ │ │ └── useGridSelection.ts
│ │ │ │ ├── popup/
│ │ │ │ │ └── useFormState.ts
│ │ │ │ ├── template/
│ │ │ │ │ └── useStringOnlyTemplate.ts
│ │ │ │ ├── timeGrid/
│ │ │ │ │ ├── useTimeGridEventMove.spec.tsx
│ │ │ │ │ ├── useTimeGridEventMove.ts
│ │ │ │ │ ├── useTimeGridEventResize.ts
│ │ │ │ │ ├── useTimeGridScrollSync.ts
│ │ │ │ │ └── useTimezoneLabelsTop.ts
│ │ │ │ └── timezone/
│ │ │ │ ├── useEventsWithTimezone.ts
│ │ │ │ ├── usePrimaryTimezone.ts
│ │ │ │ ├── useTZConverter.spec.ts
│ │ │ │ └── useTZConverter.ts
│ │ │ ├── index.ts
│ │ │ ├── jest.d.ts
│ │ │ ├── model/
│ │ │ │ ├── eventModel.spec.ts
│ │ │ │ ├── eventModel.ts
│ │ │ │ └── eventUIModel.ts
│ │ │ ├── selectors/
│ │ │ │ ├── index.ts
│ │ │ │ ├── options.ts
│ │ │ │ ├── popup.ts
│ │ │ │ ├── theme.ts
│ │ │ │ └── timezone.ts
│ │ │ ├── setupTests.ts
│ │ │ ├── slices/
│ │ │ │ ├── calendar.ts
│ │ │ │ ├── dnd.ts
│ │ │ │ ├── gridSelection.ts
│ │ │ │ ├── layout.ts
│ │ │ │ ├── options.ts
│ │ │ │ ├── popup.ts
│ │ │ │ ├── template.ts
│ │ │ │ ├── view.spec.ts
│ │ │ │ └── view.ts
│ │ │ ├── store/
│ │ │ │ ├── index.spec.tsx
│ │ │ │ ├── index.ts
│ │ │ │ └── internal.ts
│ │ │ ├── template/
│ │ │ │ ├── default.tsx
│ │ │ │ ├── index.ts
│ │ │ │ └── template.spec.tsx
│ │ │ ├── test/
│ │ │ │ ├── cssFileMock.ts
│ │ │ │ ├── helpers.ts
│ │ │ │ ├── matchers.ts
│ │ │ │ ├── testIds.ts
│ │ │ │ └── utils.tsx
│ │ │ ├── theme/
│ │ │ │ ├── common.ts
│ │ │ │ ├── dispatch.spec.tsx
│ │ │ │ ├── dispatch.ts
│ │ │ │ ├── month.ts
│ │ │ │ └── week.ts
│ │ │ ├── time/
│ │ │ │ ├── date.spec.ts
│ │ │ │ ├── date.ts
│ │ │ │ ├── datetime.spec.ts
│ │ │ │ ├── datetime.ts
│ │ │ │ ├── timezone.spec.ts
│ │ │ │ └── timezone.ts
│ │ │ ├── tui-code-snippet.d.ts
│ │ │ ├── types/
│ │ │ │ ├── components/
│ │ │ │ │ ├── common.ts
│ │ │ │ │ └── gridSelection.ts
│ │ │ │ ├── drag.ts
│ │ │ │ ├── eventBus.ts
│ │ │ │ ├── events.ts
│ │ │ │ ├── grid.ts
│ │ │ │ ├── mouse.ts
│ │ │ │ ├── options.ts
│ │ │ │ ├── panel.ts
│ │ │ │ ├── store.ts
│ │ │ │ ├── template.ts
│ │ │ │ ├── theme.ts
│ │ │ │ ├── time/
│ │ │ │ │ └── datetime.ts
│ │ │ │ └── util.ts
│ │ │ └── utils/
│ │ │ ├── array.spec.ts
│ │ │ ├── array.ts
│ │ │ ├── collection.spec.ts
│ │ │ ├── collection.ts
│ │ │ ├── dom.spec.ts
│ │ │ ├── dom.ts
│ │ │ ├── error.ts
│ │ │ ├── eventBus.ts
│ │ │ ├── keyboard.ts
│ │ │ ├── logger.ts
│ │ │ ├── math.spec.ts
│ │ │ ├── math.ts
│ │ │ ├── noop.ts
│ │ │ ├── object.spec.ts
│ │ │ ├── object.ts
│ │ │ ├── preact.ts
│ │ │ ├── requestTimeout.spec.ts
│ │ │ ├── requestTimeout.ts
│ │ │ ├── sanitizer.ts
│ │ │ ├── stamp.ts
│ │ │ ├── string.spec.ts
│ │ │ ├── string.ts
│ │ │ ├── type.spec.ts
│ │ │ └── type.ts
│ │ ├── stories/
│ │ │ ├── column.stories.tsx
│ │ │ ├── data/
│ │ │ │ └── events.json
│ │ │ ├── dayGridMonth.stories.tsx
│ │ │ ├── dayView.stories.tsx
│ │ │ ├── e2e/
│ │ │ │ ├── day.stories.tsx
│ │ │ │ ├── month.stories.tsx
│ │ │ │ └── week.stories.tsx
│ │ │ ├── eventDetailPopup.stories.tsx
│ │ │ ├── eventFormPopup.stories.tsx
│ │ │ ├── events.stories.tsx
│ │ │ ├── gridHeader.stories.tsx
│ │ │ ├── gridRow.stories.tsx
│ │ │ ├── helper/
│ │ │ │ └── event.ts
│ │ │ ├── layout.stories.tsx
│ │ │ ├── main.stories.tsx
│ │ │ ├── mocks/
│ │ │ │ ├── mockCalendars.ts
│ │ │ │ ├── mockDayViewEvents.ts
│ │ │ │ ├── mockMonthViewEvents.ts
│ │ │ │ ├── mockWeekViewEvents.ts
│ │ │ │ └── types.ts
│ │ │ ├── monthView.stories.tsx
│ │ │ ├── timegrid.stories.tsx
│ │ │ ├── util/
│ │ │ │ ├── calendarExample.tsx
│ │ │ │ ├── mockCalendarDates.ts
│ │ │ │ ├── mockCalendars.ts
│ │ │ │ ├── providerWrapper.tsx
│ │ │ │ └── randomEvents.ts
│ │ │ └── weekView.stories.tsx
│ │ ├── stylelint.config.js
│ │ ├── tsconfig.declaration.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.test.json
│ │ ├── tuidoc.config.json
│ │ ├── vite.config.ts
│ │ └── webpack.config.js
│ ├── react-calendar/
│ │ ├── .browserslistrc
│ │ ├── .eslintrc.js
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── docs/
│ │ │ ├── README.md
│ │ │ ├── en/
│ │ │ │ └── guide/
│ │ │ │ ├── getting-started.md
│ │ │ │ └── migration-guide-v2.md
│ │ │ └── ko/
│ │ │ ├── README.md
│ │ │ └── guide/
│ │ │ ├── getting-started.md
│ │ │ └── migration-guide-v2.md
│ │ ├── example/
│ │ │ ├── app.css
│ │ │ ├── app.tsx
│ │ │ ├── index.html
│ │ │ ├── main.tsx
│ │ │ ├── theme.ts
│ │ │ └── utils.ts
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.tsx
│ │ │ └── isEqual.ts
│ │ ├── tsconfig.declaration.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ └── vue-calendar/
│ ├── .eslintignore
│ ├── .eslintrc.js
│ ├── .lintstagedrc.js
│ ├── README.md
│ ├── docs/
│ │ ├── README.md
│ │ ├── en/
│ │ │ └── guide/
│ │ │ ├── getting-started.md
│ │ │ └── migration-guide-v2.md
│ │ └── ko/
│ │ ├── README.md
│ │ └── guide/
│ │ ├── getting-started.md
│ │ └── migration-guide-v2.md
│ ├── example/
│ │ ├── App.vue
│ │ ├── app.css
│ │ ├── index.html
│ │ ├── main.js
│ │ ├── mock-data.js
│ │ ├── theme.js
│ │ └── utils.js
│ ├── index.d.ts
│ ├── package.json
│ ├── src/
│ │ └── Calendar.js
│ └── vite.config.js
├── babel.config.json
├── docs/
│ ├── COMMIT_MESSAGE_CONVENTION.md
│ ├── ISSUE_TEMPLATE.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── README.md
│ ├── en/
│ │ ├── apis/
│ │ │ ├── calendar.md
│ │ │ ├── event-object.md
│ │ │ ├── options.md
│ │ │ ├── template.md
│ │ │ ├── theme.md
│ │ │ └── tzdate.md
│ │ └── guide/
│ │ ├── getting-started.md
│ │ └── migration-guide-v2.md
│ └── ko/
│ ├── README.md
│ ├── apis/
│ │ ├── calendar.md
│ │ ├── event-object.md
│ │ ├── options.md
│ │ ├── template.md
│ │ ├── theme.md
│ │ └── tzdate.md
│ └── guide/
│ ├── getting-started.md
│ └── migration-guide-v2.md
├── jest.config.js
├── libs/
│ └── date/
│ ├── .eslintrc.js
│ ├── index.d.ts
│ ├── jest.config.js
│ ├── package.json
│ ├── src/
│ │ ├── index.js
│ │ ├── localDate.js
│ │ ├── momentDate.js
│ │ └── utcDate.js
│ ├── test/
│ │ ├── localDate.spec.js
│ │ ├── momentDate.moment-timezone.spec.js
│ │ ├── momentDate.moment.spec.js
│ │ └── utcDate.spec.js
│ ├── tsBannerGenerator.js
│ ├── tuidoc.config.json
│ └── webpack.config.js
├── package.json
├── playwright.config.ts
└── scripts/
└── replaceLinkInReadme.js
SYMBOL INDEX (1199 symbols across 256 files)
FILE: apps/calendar/examples/scripts/app.js
function reloadEvents (line 32) | function reloadEvents() {
function getReadableViewName (line 44) | function getReadableViewName(viewType) {
function displayRenderRange (line 57) | function displayRenderRange() {
function setDropdownTriggerText (line 64) | function setDropdownTriggerText() {
function toggleDropdownState (line 70) | function toggleDropdownState() {
function setAllCheckboxes (line 76) | function setAllCheckboxes(checked) {
function setCheckboxBackgroundColor (line 85) | function setCheckboxBackgroundColor(checkbox) {
function update (line 104) | function update() {
function bindAppEvents (line 110) | function bindAppEvents() {
function bindInstanceEvents (line 178) | function bindInstanceEvents() {
function initCheckbox (line 217) | function initCheckbox() {
function getEventTemplate (line 225) | function getEventTemplate(event, isAllday) {
FILE: apps/calendar/examples/scripts/mock-data.js
function generateRandomEvent (line 47) | function generateRandomEvent(calendar, renderStart, renderEnd) {
function generateRandomEvents (line 149) | function generateRandomEvents(viewName, renderStart, renderEnd) {
FILE: apps/calendar/examples/scripts/utils.js
function getNavbarRange (line 10) | function getNavbarRange(tzStart, tzEnd, viewType) {
FILE: apps/calendar/playwright/assertions.ts
function assertDayGridSelectionMatching (line 9) | async function assertDayGridSelectionMatching(
function assertAccumulatedDayGridSelectionMatching (line 56) | async function assertAccumulatedDayGridSelectionMatching(
function assertBoundingBoxIncluded (line 117) | function assertBoundingBoxIncluded(targetBox: BoundingBox, wrappingBox: ...
function assertTimeGridSelection (line 124) | async function assertTimeGridSelection(
FILE: apps/calendar/playwright/configs.ts
constant PORT (line 1) | const PORT = process.env.CI ? 8080 : 6006;
constant DAY_VIEW_PAGE_URL (line 6) | const DAY_VIEW_PAGE_URL = generatePageUrl('e2e-day-view--fixed-events');
constant WEEK_VIEW_PAGE_URL (line 8) | const WEEK_VIEW_PAGE_URL = generatePageUrl('e2e-week-view--fixed-events');
constant WEEK_VIEW_TIMEZONE_PAGE_URL (line 10) | const WEEK_VIEW_TIMEZONE_PAGE_URL = generatePageUrl(
constant WEEK_VIEW_DUPLICATE_EVENTS_PAGE_URL (line 14) | const WEEK_VIEW_DUPLICATE_EVENTS_PAGE_URL = generatePageUrl(
constant WEEK_VIEW_HOUR_START_OPTION_PAGE_URL (line 18) | const WEEK_VIEW_HOUR_START_OPTION_PAGE_URL = generatePageUrl(
constant MONTH_VIEW_EMPTY_PAGE_URL (line 22) | const MONTH_VIEW_EMPTY_PAGE_URL = generatePageUrl('e2e-month-view--empty');
constant MONTH_VIEW_PAGE_URL (line 24) | const MONTH_VIEW_PAGE_URL = generatePageUrl('e2e-month-view--fixed-event...
FILE: apps/calendar/playwright/constants.ts
type ClickDelay (line 1) | enum ClickDelay {
FILE: apps/calendar/playwright/day/timeGridEventMoving.e2e.ts
constant MOVE_EVENT_SELECTOR (line 23) | const MOVE_EVENT_SELECTOR = '[class*="dragging--move-event"]';
constant DRAG_START_TIME (line 26) | const DRAG_START_TIME = '04:00';
constant ONE_DAY_TIME_EVENTS (line 202) | const ONE_DAY_TIME_EVENTS = mockDayViewEvents.filter(
FILE: apps/calendar/playwright/day/timeGridEventResizing.e2e.ts
constant RESIZE_HANDLER_SELECTOR (line 23) | const RESIZE_HANDLER_SELECTOR = '[class*="resize-handler"]';
constant RESIZE_EVENT_SELECTOR (line 24) | const RESIZE_EVENT_SELECTOR = '[class*="dragging--resize-vertical-event"]';
function setup (line 43) | async function setup({
FILE: apps/calendar/playwright/day/timeGridScrollSync.e2e.ts
function getScrollTop (line 15) | function getScrollTop(el: HTMLElement) {
function setup (line 23) | async function setup(page: Page) {
function setup (line 118) | async function setup(page: Page) {
FILE: apps/calendar/playwright/day/timeGridSelection.e2e.ts
constant GRID_SELECTION_SELECTOR (line 17) | const GRID_SELECTION_SELECTOR = '[data-testid*="time-grid-selection"]';
FILE: apps/calendar/playwright/month/eventMoving.e2e.ts
constant MOVE_EVENT_SELECTOR (line 20) | const MOVE_EVENT_SELECTOR = '[class*="dragging--move-event"]';
function setup (line 61) | async function setup(page: Page, event: EventObject, targetCellIndex: nu...
FILE: apps/calendar/playwright/month/eventResizing.e2e.ts
constant RESIZE_EVENT_SELECTOR (line 19) | const RESIZE_EVENT_SELECTOR = '[class*="dragging--resize-horizontal-even...
function getResizeIconLocatorOfEvent (line 23) | function getResizeIconLocatorOfEvent(eventLocator: Locator) {
FILE: apps/calendar/playwright/month/gridSelection.e2e.ts
constant MONTH_GRID_CELL_SELECTOR (line 13) | const MONTH_GRID_CELL_SELECTOR = getPrefixedClassName('daygrid-cell');
constant GRID_SELECTION_SELECTOR (line 14) | const GRID_SELECTION_SELECTOR = `${getPrefixedClassName('weekday')} > ${...
function assertMonthGridSelectionMatching (line 31) | function assertMonthGridSelectionMatching(page: Page, startIndex: number...
FILE: apps/calendar/playwright/playwright-env.d.ts
type Window (line 4) | interface Window {
FILE: apps/calendar/playwright/types.ts
type BoundingBox (line 1) | type BoundingBox = {
type Direction (line 8) | enum Direction {
FILE: apps/calendar/playwright/utils.ts
function getPrefixedClassName (line 9) | function getPrefixedClassName(className: string) {
function dragAndDrop (line 13) | async function dragAndDrop({
function selectGridCells (line 44) | async function selectGridCells(
function selectMonthGridCells (line 56) | function selectMonthGridCells(page: Page, startCellIndex: number, endCel...
function getBoundingBox (line 60) | async function getBoundingBox(locator: Locator): Promise<BoundingBox> {
function getTimeEventSelector (line 70) | function getTimeEventSelector(title: string): string {
function getGuideTimeEventSelector (line 74) | function getGuideTimeEventSelector(): string {
function getHorizontalEventSelector (line 78) | function getHorizontalEventSelector(event: EventObject): string {
function getTimeGridLineSelector (line 82) | function getTimeGridLineSelector(start: FormattedTimeString): string {
function getCellSelector (line 86) | function getCellSelector(cellIndex: number): string {
function getTimeStrFromDate (line 90) | function getTimeStrFromDate(d: TZDate) {
function waitForSingleElement (line 99) | function waitForSingleElement(locator: Locator) {
function queryLocatorByTestId (line 106) | function queryLocatorByTestId(page: Page, testId: string) {
FILE: apps/calendar/playwright/week/alldayGridEventMoving.e2e.ts
constant ALL_DAY_GRID_CELL_SELECTOR (line 17) | const ALL_DAY_GRID_CELL_SELECTOR = `${getPrefixedClassName(
constant MOVE_EVENT_SELECTOR (line 20) | const MOVE_EVENT_SELECTOR = '[class*="dragging--move-event"]';
constant TARGET_EVENT_SELECTOR (line 23) | const TARGET_EVENT_SELECTOR = getHorizontalEventSelector(TARGET_EVENT);
function getX (line 25) | async function getX(locator: Locator) {
function getWidth (line 31) | async function getWidth(locator: Locator) {
FILE: apps/calendar/playwright/week/alldayGridEventResizing.e2e.ts
constant ALL_DAY_GRID_CELL_SELECTOR (line 17) | const ALL_DAY_GRID_CELL_SELECTOR = `${getPrefixedClassName(
constant RESIZE_HANDLER_SELECTOR (line 20) | const RESIZE_HANDLER_SELECTOR = getPrefixedClassName('handle-y');
constant RESIZE_EVENT_SELECTOR (line 21) | const RESIZE_EVENT_SELECTOR = '[class*="dragging--resize-horizontal-even...
constant TARGET_EVENT_SELECTOR (line 24) | const TARGET_EVENT_SELECTOR = getHorizontalEventSelector(TARGET_EVENT);
function getWidth (line 26) | async function getWidth(locator: Locator) {
FILE: apps/calendar/playwright/week/dayGridSelection.e2e.ts
constant WEEK_GRID_CELL_SELECTOR (line 13) | const WEEK_GRID_CELL_SELECTOR = getPrefixedClassName('panel-grid');
constant DAY_GRID_SELECTION_SELECTOR (line 14) | const DAY_GRID_SELECTION_SELECTOR = getPrefixedClassName('grid-selection');
function selectWeekGridCells (line 16) | function selectWeekGridCells(page: Page, startCellIndex: number, endCell...
function assertWeekGridSelectionMatching (line 20) | function assertWeekGridSelectionMatching(page: Page, startIndex: number,...
FILE: apps/calendar/playwright/week/primaryTimezone.e2e.ts
constant TARGET_TIMEZONE_HOUR_DIFFERENCE (line 10) | const TARGET_TIMEZONE_HOUR_DIFFERENCE = 4;
FILE: apps/calendar/playwright/week/timeGridEventMoving.e2e.ts
constant TIME_EVENTS (line 23) | const TIME_EVENTS = mockWeekViewEvents.filter(({ isAllday }) => !isAllday);
constant MOVE_EVENT_SELECTOR (line 26) | const MOVE_EVENT_SELECTOR = '[class*="dragging--move-event"]';
constant ONE_DAY_TIME_EVENTS (line 345) | const ONE_DAY_TIME_EVENTS = mockWeekViewEvents.filter(
FILE: apps/calendar/playwright/week/timeGridEventResizing.e2e.ts
constant RESIZE_HANDLER_SELECTOR (line 25) | const RESIZE_HANDLER_SELECTOR = '[class*="resize-handler"]';
constant RESIZE_EVENT_SELECTOR (line 26) | const RESIZE_EVENT_SELECTOR = '[class*="dragging--resize-vertical-event"]';
function getHourDifference (line 28) | function getHourDifference(minuend: FormattedTimeString, subtrahend: For...
type EventInfo (line 32) | interface EventInfo {
function setup (line 94) | async function setup({
function setupResizingGoingOrComingDuration (line 289) | async function setupResizingGoingOrComingDuration(
FILE: apps/calendar/playwright/week/timeGridScrollSync.e2e.ts
function getScrollTop (line 14) | function getScrollTop(el: HTMLElement) {
function setup (line 22) | async function setup(page: Page) {
function setup (line 110) | async function setup(page: Page) {
FILE: apps/calendar/playwright/week/timeGridSelection.e2e.ts
constant GRID_SELECTION_SELECTOR (line 8) | const GRID_SELECTION_SELECTOR = '[data-testid*="time-grid-selection"]';
FILE: apps/calendar/scripts/publishToCDN.js
constant LOCAL_DIST_PATH (line 7) | const LOCAL_DIST_PATH = path.join(__dirname, '../dist');
constant STORAGE_API_URL (line 8) | const STORAGE_API_URL = 'https://api-storage.cloud.toast.com/v1';
constant IDENTITY_API_URL (line 9) | const IDENTITY_API_URL = 'https://api-identity.infrastructure.cloud.toas...
constant TOAST_CLOUD_TENANTID (line 11) | const TOAST_CLOUD_TENANTID = process.env.TOAST_CLOUD_TENANTID;
constant TOAST_CLOUD_STORAGEID (line 12) | const TOAST_CLOUD_STORAGEID = process.env.TOAST_CLOUD_STORAGEID;
constant TOAST_CLOUD_USERNAME (line 13) | const TOAST_CLOUD_USERNAME = process.env.TOAST_CLOUD_USERNAME;
constant TOAST_CLOUD_PASSWORD (line 14) | const TOAST_CLOUD_PASSWORD = process.env.TOAST_CLOUD_PASSWORD;
function getTOASTCloudContainer (line 16) | async function getTOASTCloudContainer(token) {
function getTOASTCloudToken (line 29) | async function getTOASTCloudToken() {
function publishToCdn (line 50) | function publishToCdn(token, localPath, cdnPath) {
function publish (line 78) | async function publish() {
FILE: apps/calendar/scripts/updateWrapper.js
constant CORE_PACKAGE_JSON_PATH (line 5) | const CORE_PACKAGE_JSON_PATH = path.join(__dirname, '../package.json');
constant REACT_PACKAGE_JSON_PATH (line 6) | const REACT_PACKAGE_JSON_PATH = path.join(__dirname, '../../react-calend...
constant VUE_PACKAGE_JSON_PATH (line 7) | const VUE_PACKAGE_JSON_PATH = path.join(__dirname, '../../vue-calendar/p...
FILE: apps/calendar/src/calendarContainer.tsx
type Props (line 14) | interface Props {
function CalendarContainer (line 20) | function CalendarContainer({ theme, store, eventBus, children }: PropsWi...
FILE: apps/calendar/src/components/dayGridCommon/dayName.tsx
type Props (line 16) | interface Props {
function isWeekDayName (line 23) | function isWeekDayName(
function getWeekDayNameColor (line 30) | function getWeekDayNameColor({
function getMonthDayNameColor (line 59) | function getMonthDayNameColor({
function DayName (line 78) | function DayName({ dayName, style, type, theme }: Props) {
FILE: apps/calendar/src/components/dayGridCommon/gridHeader.tsx
type TemplateDayNames (line 14) | type TemplateDayNames = (TemplateWeekDayName | TemplateMonthDayName)[];
type DayNameThemes (line 16) | type DayNameThemes = {
type Props (line 33) | interface Props {
function weekDayNameSelector (line 41) | function weekDayNameSelector(theme: ThemeState): DayNameThemes {
function monthDayNameSelector (line 57) | function monthDayNameSelector(theme: ThemeState): DayNameThemes {
function GridHeader (line 71) | function GridHeader({
FILE: apps/calendar/src/components/dayGridCommon/gridSelection.tsx
type Props (line 11) | interface Props {
function commonGridSelectionSelector (line 18) | function commonGridSelectionSelector(theme: ThemeState) {
function GridSelection (line 22) | function GridSelection({ type, gridSelectionData, weekDates, narrowWeeke...
FILE: apps/calendar/src/components/dayGridMonth/accumulatedGridSelection.tsx
type Props (line 10) | interface Props {
function AccumulatedGridSelection (line 16) | function AccumulatedGridSelection({ rowIndex, weekDates, narrowWeekend }...
FILE: apps/calendar/src/components/dayGridMonth/cellHeader.tsx
type Props (line 20) | interface Props {
function getDateColor (line 27) | function getDateColor({
function useCellHeaderTheme (line 66) | function useCellHeaderTheme() {
function CellHeader (line 73) | function CellHeader({
FILE: apps/calendar/src/components/dayGridMonth/dayGridMonth.tsx
constant TOTAL_PERCENT_HEIGHT (line 34) | const TOTAL_PERCENT_HEIGHT = 100;
type Props (line 36) | interface Props {
function useCellContentAreaHeight (line 42) | function useCellContentAreaHeight(eventHeight: number) {
function DayGridMonth (line 66) | function DayGridMonth({ dateMatrix = [], rowInfo = [], cellWidthMap = []...
FILE: apps/calendar/src/components/dayGridMonth/gridCell.tsx
type RectSize (line 30) | interface RectSize {
type SeeMoreRectParam (line 35) | type SeeMoreRectParam = {
function getSeeMorePopupSize (line 41) | function getSeeMorePopupSize({
function getSeeMorePopupPosition (line 88) | function getSeeMorePopupPosition(popupSize: RectSize, appContainerSize: ...
function getSeeMorePopupRect (line 127) | function getSeeMorePopupRect({
function usePopupPosition (line 140) | function usePopupPosition(
function weekendBackgroundColorSelector (line 175) | function weekendBackgroundColorSelector(theme: ThemeState) {
type Props (line 179) | interface Props {
function GridCell (line 187) | function GridCell({ date, events = [], style, parentContainer, contentAr...
FILE: apps/calendar/src/components/dayGridMonth/gridRow.tsx
type Props (line 15) | interface Props {
FILE: apps/calendar/src/components/dayGridMonth/gridSelectionByRow.tsx
type Props (line 12) | interface Props {
function GridSelectionByRow (line 18) | function GridSelectionByRow({ weekDates, narrowWeekend, rowIndex }: Prop...
FILE: apps/calendar/src/components/dayGridMonth/monthEvents.tsx
type Props (line 11) | interface Props {
FILE: apps/calendar/src/components/dayGridMonth/moreEventsButton.tsx
type Props (line 8) | interface Props {
function MoreEventsButton (line 15) | function MoreEventsButton({ type, number, onClickButton, className }: Pr...
FILE: apps/calendar/src/components/dayGridMonth/movingEventShadow.tsx
type Props (line 13) | type Props = Pick<ComponentProps<typeof DayGridMonth>, 'dateMatrix' | 'r...
function MovingEventShadow (line 18) | function MovingEventShadow({ dateMatrix, gridPositionFinder, rowInfo, ro...
FILE: apps/calendar/src/components/dayGridMonth/resizingGuideByRow.tsx
type Props (line 18) | type Props = Pick<ComponentProps<typeof DayGridMonth>, 'dateMatrix' | 'c...
function ResizingGuideByRow (line 24) | function ResizingGuideByRow({
FILE: apps/calendar/src/components/dayGridWeek/alldayGridRow.tsx
type Props (line 28) | interface Props {
function AlldayGridRow (line 42) | function AlldayGridRow({
FILE: apps/calendar/src/components/dayGridWeek/alldayGridSelection.tsx
function dayGridWeekSelectionSelector (line 12) | function dayGridWeekSelectionSelector(state: CalendarState) {
type Props (line 16) | type Props = Pick<ComponentProps<typeof AlldayGridRow>, 'weekDates'> & {
function AlldayGridSelection (line 20) | function AlldayGridSelection({ weekDates, narrowWeekend }: Props) {
FILE: apps/calendar/src/components/dayGridWeek/gridCell.tsx
type Props (line 8) | type Props = {
type ExceedCountProps (line 15) | interface ExceedCountProps {
type CollapseButtonProps (line 22) | interface CollapseButtonProps {
function ExceedCount (line 28) | function ExceedCount({ index, exceedCount, isClicked, onClickExceedCount...
function CollapseButton (line 39) | function CollapseButton({ isClicked, isClickedIndex, onClickCollapseButt...
function GridCell (line 47) | function GridCell({
FILE: apps/calendar/src/components/dayGridWeek/gridCells.tsx
type Props (line 16) | interface Props {
FILE: apps/calendar/src/components/dayGridWeek/movingEventShadow.tsx
type Props (line 12) | type Props = Pick<ComponentProps<typeof AlldayGridRow>, 'rowStyleInfo'> & {
function MovingEventShadow (line 16) | function MovingEventShadow({
FILE: apps/calendar/src/components/dayGridWeek/otherGridRow.tsx
type GridRowTitleTemplate (line 19) | type GridRowTitleTemplate = `${AlldayEventCategory}Title`;
type Props (line 21) | interface Props {
function OtherGridRow (line 32) | function OtherGridRow({
FILE: apps/calendar/src/components/dayGridWeek/resizingEventShadow.tsx
type Props (line 12) | type Props = Pick<ComponentProps<typeof AlldayGridRow>, 'weekDates' | 'g...
function ResizingEventShadow (line 16) | function ResizingEventShadow({ weekDates, gridColWidthMap, gridPositionF...
FILE: apps/calendar/src/components/events/backgroundEvent.tsx
type Props (line 10) | interface Props {
function BackgroundEvent (line 20) | function BackgroundEvent({
FILE: apps/calendar/src/components/events/horizontalEvent.spec.tsx
function setup (line 14) | function setup() {
function setup (line 78) | function setup() {
function setup (line 335) | function setup() {
FILE: apps/calendar/src/components/events/horizontalEvent.tsx
type Props (line 23) | interface Props {
function getMargins (line 32) | function getMargins(flat: boolean) {
function getBorderRadius (line 39) | function getBorderRadius(exceedLeft: boolean, exceedRight: boolean): str...
function getEventItemStyle (line 46) | function getEventItemStyle({
function getContainerStyle (line 86) | function getContainerStyle({
function getTestId (line 109) | function getTestId({ model }: EventUIModel) {
function HorizontalEvent (line 125) | function HorizontalEvent({
FILE: apps/calendar/src/components/events/horizontalEventResizeIcon.tsx
type Props (line 7) | interface Props {
function HorizontalEventResizeIcon (line 11) | function HorizontalEventResizeIcon({ onMouseDown }: Props) {
FILE: apps/calendar/src/components/events/timeEvent.spec.tsx
function setup (line 16) | function setup() {
function setup (line 79) | function setup() {
FILE: apps/calendar/src/components/events/timeEvent.tsx
type Props (line 33) | interface Props {
function getMarginLeft (line 40) | function getMarginLeft(left: number | string) {
function getContainerWidth (line 46) | function getContainerWidth(width: number | string, marginLeft: number) {
function getStyles (line 57) | function getStyles({
function isDraggableEvent (line 137) | function isDraggableEvent({
function TimeEvent (line 153) | function TimeEvent({
FILE: apps/calendar/src/components/layout.tsx
type Props (line 21) | interface Props {
function getLayoutStylesFromInfo (line 29) | function getLayoutStylesFromInfo(width?: number, height?: number) {
function Layout (line 43) | function Layout({
FILE: apps/calendar/src/components/panel.tsx
type Props (line 15) | interface Props {
function getPanelSide (line 38) | function getPanelSide(side: number, maxExpandableSide?: number) {
function getPanelStyle (line 42) | function getPanelStyle({
FILE: apps/calendar/src/components/panelResizer.tsx
type Props (line 13) | interface Props {
function getDefaultStyle (line 19) | function getDefaultStyle(height: number, border: string) {
function PanelResizer (line 29) | function PanelResizer({ name, height }: Props) {
FILE: apps/calendar/src/components/popup/calendarDropdownMenu.tsx
type Props (line 7) | interface Props {
type DropdownMenuItemProps (line 14) | interface DropdownMenuItemProps {
function DropdownMenuItem (line 28) | function DropdownMenuItem({ index, name, backgroundColor, onClick }: Dro...
function CalendarDropdownMenu (line 37) | function CalendarDropdownMenu({ calendars, setOpened, onChangeIndex }: P...
FILE: apps/calendar/src/components/popup/calendarSelector.tsx
type Props (line 12) | interface Props {
function CalendarSelector (line 25) | function CalendarSelector({ calendars, selectedCalendarId, formStateDisp...
FILE: apps/calendar/src/components/popup/closePopupButton.tsx
type Props (line 8) | interface Props {
function ClosePopupButton (line 18) | function ClosePopupButton({ type, close }: Props) {
FILE: apps/calendar/src/components/popup/confirmPopupButton.tsx
function ConfirmPopupButton (line 11) | function ConfirmPopupButton({ children }: PropsWithChildren) {
FILE: apps/calendar/src/components/popup/dateSelector.tsx
type Props (line 19) | interface Props {
FILE: apps/calendar/src/components/popup/eventDetailPopup.spec.tsx
function setup (line 52) | function setup(options: Options = {}) {
FILE: apps/calendar/src/components/popup/eventDetailPopup.tsx
function calculatePopupPosition (line 39) | function calculatePopupPosition(eventRect: Rect, layoutRect: Rect, popup...
function calculatePopupArrowPosition (line 57) | function calculatePopupArrowPosition(eventRect: Rect, layoutRect: Rect, ...
function EventDetailPopup (line 69) | function EventDetailPopup() {
FILE: apps/calendar/src/components/popup/eventDetailSectionDetail.tsx
type Props (line 8) | interface Props {
function EventDetailSectionDetail (line 26) | function EventDetailSectionDetail({ event }: Props) {
FILE: apps/calendar/src/components/popup/eventDetailSectionHeader.tsx
type Props (line 7) | interface Props {
function EventDetailSectionHeader (line 17) | function EventDetailSectionHeader({ event }: Props) {
FILE: apps/calendar/src/components/popup/eventFormPopup.tsx
function calculatePopupPosition (line 46) | function calculatePopupPosition(
function isBooleanKey (line 75) | function isBooleanKey(key: string): key is BooleanKeyOfEventObject {
function getChanges (line 79) | function getChanges(event: EventModel, eventObject: EventObject) {
function EventFormPopup (line 96) | function EventFormPopup() {
FILE: apps/calendar/src/components/popup/eventStateSelector.tsx
type Props (line 13) | interface Props {
function EventStateSelector (line 26) | function EventStateSelector({ eventState = 'Busy', formStateDispatch }: ...
FILE: apps/calendar/src/components/popup/locationInputBox.tsx
type Props (line 10) | interface Props {
function LocationInputBox (line 21) | function LocationInputBox({ location, formStateDispatch }: Props) {
FILE: apps/calendar/src/components/popup/popupOverlay.tsx
function shownPopupParamSelector (line 8) | function shownPopupParamSelector(state: CalendarState) {
function PopupOverlay (line 12) | function PopupOverlay() {
FILE: apps/calendar/src/components/popup/popupSection.tsx
type Props (line 8) | interface Props {
function PopupSection (line 13) | function PopupSection({
FILE: apps/calendar/src/components/popup/seeMoreEventsPopup.tsx
function SeeMoreEventsPopup (line 31) | function SeeMoreEventsPopup() {
FILE: apps/calendar/src/components/popup/stateDropdownMenu.tsx
type Props (line 8) | interface Props {
constant EVENT_STATES (line 13) | const EVENT_STATES: EventState[] = ['Busy', 'Free'];
function StateDropdownMenu (line 21) | function StateDropdownMenu({ setOpened, setEventState }: Props) {
FILE: apps/calendar/src/components/popup/titleInputBox.tsx
type Props (line 10) | interface Props {
function TitleInputBox (line 23) | function TitleInputBox({ title, isPrivate = false, formStateDispatch }: ...
FILE: apps/calendar/src/components/template.tsx
type Props (line 12) | interface Props {
function Template (line 18) | function Template({ template, param, as: tagName = 'div' }: Props) {
FILE: apps/calendar/src/components/timeGrid/column.tsx
function VerticalEvents (line 60) | function VerticalEvents({
function backgroundColorSelector (line 83) | function backgroundColorSelector(theme: ThemeState) {
function getBackgroundColor (line 91) | function getBackgroundColor({
type Props (line 118) | interface Props {
FILE: apps/calendar/src/components/timeGrid/gridLines.tsx
function gridLineBorderSelector (line 10) | function gridLineBorderSelector(theme: ThemeState) {
FILE: apps/calendar/src/components/timeGrid/gridSelectionByColumn.tsx
function GridSelection (line 13) | function GridSelection({ top, height, text }: { top: number; height: num...
type Props (line 41) | interface Props {
function GridSelectionByColumn (line 46) | function GridSelectionByColumn({ columnIndex, timeGridRows }: Props) {
FILE: apps/calendar/src/components/timeGrid/movingEventShadow.tsx
function MovingEventShadow (line 9) | function MovingEventShadow({
FILE: apps/calendar/src/components/timeGrid/nowIndicator.tsx
type Props (line 22) | interface Props {
function nowIndicatorTheme (line 29) | function nowIndicatorTheme(theme: ThemeState) {
function NowIndicator (line 38) | function NowIndicator({ top, columnWidth, columnCount, columnIndex }: Pr...
FILE: apps/calendar/src/components/timeGrid/nowIndicatorLabel.tsx
type Props (line 19) | interface Props {
function NowIndicatorLabel (line 26) | function NowIndicatorLabel({ unit, top, now, zonedNow }: Props) {
FILE: apps/calendar/src/components/timeGrid/resizingGuideByColumn.tsx
function ResizingGuideByColumn (line 10) | function ResizingGuideByColumn({
FILE: apps/calendar/src/components/timeGrid/timeColumn.tsx
type HourRowsProps (line 35) | interface HourRowsProps {
function backgroundColorSelector (line 51) | function backgroundColorSelector(theme: ThemeState) {
function timeColorSelector (line 58) | function timeColorSelector(theme: ThemeState) {
function HourRows (line 65) | function HourRows({ rowsInfo, isPrimary, borderRight, width, nowIndicato...
type Props (line 116) | interface Props {
FILE: apps/calendar/src/components/timeGrid/timeGrid.tsx
type Props (line 46) | interface Props {
function TimeGrid (line 51) | function TimeGrid({ timeGridData, events }: Props) {
FILE: apps/calendar/src/components/timeGrid/timezoneCollapseButton.tsx
function TimezoneCollapseButton (line 7) | function TimezoneCollapseButton({ isCollapsed }: { isCollapsed: boolean ...
FILE: apps/calendar/src/components/timeGrid/timezoneLabels.tsx
type TimezoneLabelProps (line 19) | interface TimezoneLabelProps {
function TimezoneLabel (line 27) | function TimezoneLabel({ label, offset, tooltip, width = 100, left }: Ti...
function useTimezoneCollapseOptions (line 48) | function useTimezoneCollapseOptions() {
function TimezoneLabels (line 60) | function TimezoneLabels({ top }: { top: number | null }) {
FILE: apps/calendar/src/components/view/day.spec.tsx
function setup (line 16) | function setup(options: Options, events?: EventModel[]) {
FILE: apps/calendar/src/components/view/day.tsx
function useDayViewState (line 34) | function useDayViewState() {
function Day (line 52) | function Day() {
FILE: apps/calendar/src/components/view/main.tsx
function Main (line 21) | function Main() {
FILE: apps/calendar/src/components/view/month.spec.tsx
function setup (line 14) | function setup(options: Options, events?: EventModel[]) {
FILE: apps/calendar/src/components/view/month.tsx
function getMonthDayNames (line 18) | function getMonthDayNames(options: CalendarStore['options']) {
function Month (line 29) | function Month() {
FILE: apps/calendar/src/components/view/week.spec.tsx
function setup (line 17) | function setup(options: Options, events?: EventModel[]) {
FILE: apps/calendar/src/components/view/week.tsx
function useWeekViewState (line 35) | function useWeekViewState() {
function Week (line 53) | function Week() {
FILE: apps/calendar/src/constants/error.ts
constant INVALID_DATETIME_FORMAT (line 1) | const INVALID_DATETIME_FORMAT = 'Invalid DateTime Format';
constant INVALID_TIMEZONE_NAME (line 2) | const INVALID_TIMEZONE_NAME = 'Invalid IANA Timezone Name';
constant INVALID_VIEW_TYPE (line 3) | const INVALID_VIEW_TYPE = 'Invalid View Type';
FILE: apps/calendar/src/constants/grid.ts
constant DEFAULT_VISIBLE_WEEKS (line 1) | const DEFAULT_VISIBLE_WEEKS = 6;
type CellBarType (line 3) | enum CellBarType {
FILE: apps/calendar/src/constants/keyboard.ts
type KEY (line 1) | enum KEY {
constant KEYCODE (line 5) | const KEYCODE: Record<KEY, number> = {
FILE: apps/calendar/src/constants/layout.ts
constant DEFAULT_RESIZER_LENGTH (line 1) | const DEFAULT_RESIZER_LENGTH = 3;
constant DEFAULT_DUPLICATE_EVENT_CID (line 3) | const DEFAULT_DUPLICATE_EVENT_CID = -1;
FILE: apps/calendar/src/constants/message.ts
constant MESSAGE_PREFIX (line 1) | const MESSAGE_PREFIX = '@toast-ui/calendar: ';
FILE: apps/calendar/src/constants/mouse.ts
constant MINIMUM_DRAG_MOUSE_DISTANCE (line 1) | const MINIMUM_DRAG_MOUSE_DISTANCE = 3;
FILE: apps/calendar/src/constants/popup.ts
constant SEE_MORE_POPUP_SLOT_CLASS_NAME (line 5) | const SEE_MORE_POPUP_SLOT_CLASS_NAME = cls('see-more-popup-slot');
constant EVENT_FORM_POPUP_SLOT_CLASS_NAME (line 6) | const EVENT_FORM_POPUP_SLOT_CLASS_NAME = cls('event-form-popup-slot');
constant EVENT_DETAIL_POPUP_SLOT_CLASS_NAME (line 7) | const EVENT_DETAIL_POPUP_SLOT_CLASS_NAME = cls('event-detail-popup-slot');
constant HALF_OF_POPUP_ARROW_HEIGHT (line 9) | const HALF_OF_POPUP_ARROW_HEIGHT = 8;
constant BOOLEAN_KEYS_OF_EVENT_MODEL_DATA (line 11) | const BOOLEAN_KEYS_OF_EVENT_MODEL_DATA: BooleanKeyOfEventObject[] = [
type DetailPopupArrowDirection (line 20) | enum DetailPopupArrowDirection {
type FormPopupArrowDirection (line 25) | enum FormPopupArrowDirection {
FILE: apps/calendar/src/constants/statistics.ts
constant GA_TRACKING_ID (line 1) | const GA_TRACKING_ID = 'UA-129951699-1';
FILE: apps/calendar/src/constants/style.ts
constant DEFAULT_DAY_NAME_MARGIN_LEFT (line 2) | const DEFAULT_DAY_NAME_MARGIN_LEFT = '0';
constant MONTH_DAY_NAME_HEIGHT (line 5) | const MONTH_DAY_NAME_HEIGHT = 31;
constant MONTH_EVENT_BORDER_RADIUS (line 8) | const MONTH_EVENT_BORDER_RADIUS = 2;
constant MONTH_EVENT_HEIGHT (line 9) | const MONTH_EVENT_HEIGHT = 24;
constant MONTH_EVENT_MARGIN_TOP (line 10) | const MONTH_EVENT_MARGIN_TOP = 2;
constant MONTH_EVENT_MARGIN_LEFT (line 11) | const MONTH_EVENT_MARGIN_LEFT = 8;
constant MONTH_EVENT_MARGIN_RIGHT (line 12) | const MONTH_EVENT_MARGIN_RIGHT = 8;
constant MONTH_CELL_PADDING_TOP (line 15) | const MONTH_CELL_PADDING_TOP = 3;
constant MONTH_CELL_BAR_HEIGHT (line 16) | const MONTH_CELL_BAR_HEIGHT = 27;
constant MONTH_MORE_VIEW_PADDING (line 19) | const MONTH_MORE_VIEW_PADDING = 5;
constant MONTH_MORE_VIEW_MIN_WIDTH (line 20) | const MONTH_MORE_VIEW_MIN_WIDTH = 280;
constant MONTH_MORE_VIEW_HEADER_HEIGHT (line 21) | const MONTH_MORE_VIEW_HEADER_HEIGHT = 44;
constant MONTH_MORE_VIEW_HEADER_MARGIN_BOTTOM (line 22) | const MONTH_MORE_VIEW_HEADER_MARGIN_BOTTOM = 12;
constant MONTH_MORE_VIEW_HEADER_PADDING_TOP (line 23) | const MONTH_MORE_VIEW_HEADER_PADDING_TOP = 12;
constant MONTH_MORE_VIEW_HEADER_PADDING (line 24) | const MONTH_MORE_VIEW_HEADER_PADDING = '12px 17px 0';
constant WEEK_DAY_NAME_HEIGHT (line 27) | const WEEK_DAY_NAME_HEIGHT = 42;
constant WEEK_DAY_NAME_BORDER (line 28) | const WEEK_DAY_NAME_BORDER = 1;
constant WEEK_PANEL_RESIZER_HEIGHT (line 31) | const WEEK_PANEL_RESIZER_HEIGHT = 3;
constant WEEK_EVENT_BORDER_RADIUS (line 34) | const WEEK_EVENT_BORDER_RADIUS = 2;
constant WEEK_EVENT_HEIGHT (line 35) | const WEEK_EVENT_HEIGHT = 24;
constant WEEK_EVENT_MARGIN_TOP (line 36) | const WEEK_EVENT_MARGIN_TOP = 2;
constant WEEK_EVENT_MARGIN_LEFT (line 37) | const WEEK_EVENT_MARGIN_LEFT = 8;
constant WEEK_EVENT_MARGIN_RIGHT (line 38) | const WEEK_EVENT_MARGIN_RIGHT = 8;
constant DEFAULT_PANEL_HEIGHT (line 40) | const DEFAULT_PANEL_HEIGHT = 72;
constant DEFAULT_EVENT_COLORS (line 43) | const DEFAULT_EVENT_COLORS = {
constant TIME_EVENT_CONTAINER_MARGIN_LEFT (line 50) | const TIME_EVENT_CONTAINER_MARGIN_LEFT = 2;
constant COLLAPSED_DUPLICATE_EVENT_WIDTH_PX (line 52) | const COLLAPSED_DUPLICATE_EVENT_WIDTH_PX = 9;
FILE: apps/calendar/src/constants/theme.ts
constant DEFAULT_COMMON_THEME (line 5) | const DEFAULT_COMMON_THEME: DeepRequired<CommonTheme> = {
constant DEFAULT_WEEK_THEME (line 26) | const DEFAULT_WEEK_THEME: DeepRequired<WeekTheme> = {
constant DEFAULT_MONTH_THEME (line 98) | const DEFAULT_MONTH_THEME: DeepRequired<MonthTheme> = {
FILE: apps/calendar/src/constants/view.ts
constant VIEW_TYPE (line 3) | const VIEW_TYPE: {
constant DEFAULT_TASK_PANEL (line 11) | const DEFAULT_TASK_PANEL: TaskView[] = ['milestone', 'task'];
constant DEFAULT_EVENT_PANEL (line 13) | const DEFAULT_EVENT_PANEL: EventView[] = ['allday', 'time'];
FILE: apps/calendar/src/contexts/calendarStore.ts
function useDispatch (line 51) | function useDispatch<Group extends keyof Dispatchers>(group?: Group) {
FILE: apps/calendar/src/contexts/eventBus.spec.tsx
function wrapMockHandler (line 95) | function wrapMockHandler(mockFn: jest.Mock) {
function MultipleHandlerComponent (line 101) | function MultipleHandlerComponent() {
FILE: apps/calendar/src/contexts/floatingLayer.tsx
type FloatingLayers (line 15) | interface FloatingLayers {
type FloatingLayerType (line 22) | type FloatingLayerType = keyof FloatingLayers;
function FloatingLayerProvider (line 26) | function FloatingLayerProvider({ children }: PropsWithChildren) {
FILE: apps/calendar/src/contexts/themeStore.tsx
function useThemeDispatch (line 45) | function useThemeDispatch(): ThemeDispatchers {
function useCommonTheme (line 49) | function useCommonTheme(): CommonTheme {
function useWeekTheme (line 53) | function useWeekTheme(): WeekTheme {
function useMonthTheme (line 57) | function useMonthTheme(): MonthTheme {
function useAllTheme (line 61) | function useAllTheme(): ThemeState {
FILE: apps/calendar/src/controller/base.spec.ts
type CompatableEvent (line 184) | type CompatableEvent = Record<string, any>;
FILE: apps/calendar/src/controller/base.ts
function createEventCollection (line 15) | function createEventCollection<T extends EventModel | EventUIModel>(...i...
function getDateRange (line 30) | function getDateRange(start: TZDate, end: TZDate) {
function isAllday (line 34) | function isAllday(event: EventModel) {
function filterByCategory (line 47) | function filterByCategory(uiModel: EventUIModel) {
function addToMatrix (line 66) | function addToMatrix(idsOfDay: IDS_OF_DAY, event: EventModel) {
function removeFromMatrix (line 82) | function removeFromMatrix(idsOfDay: IDS_OF_DAY, event: EventModel) {
function addEvent (line 94) | function addEvent(calendarData: CalendarData, event: EventModel) {
function createEvent (line 101) | function createEvent(calendarData: CalendarData, eventData: EventObject) {
function createEvents (line 107) | function createEvents(calendarData: CalendarData, events: EventObject[] ...
function updateEvent (line 119) | function updateEvent(
function deleteEvent (line 146) | function deleteEvent(calendarData: CalendarData, event: EventModel) {
function clearEvents (line 153) | function clearEvents(calendarData: CalendarData) {
function setCalendars (line 163) | function setCalendars(calendarData: CalendarData, calendars: CalendarInf...
function findByDateRange (line 175) | function findByDateRange(
FILE: apps/calendar/src/controller/column.spec.ts
function createEventUIModels (line 13) | function createEventUIModels(data: EventObject[]): EventUIModel[] {
function createCurrentDateWithTime (line 17) | function createCurrentDateWithTime(h: number, m: number) {
method getDuplicateEvents (line 81) | getDuplicateEvents(targetEvent, events) {
method getMainEvent (line 86) | getMainEvent(events) {
method getDuplicateEvents (line 120) | getDuplicateEvents(targetEvent, events) {
method getMainEvent (line 125) | getMainEvent(events) {
FILE: apps/calendar/src/controller/column.ts
constant MIN_HEIGHT_PERCENT (line 17) | const MIN_HEIGHT_PERCENT = 1;
type RenderInfoOptions (line 19) | interface RenderInfoOptions {
function isBetween (line 38) | function isBetween(startColumnTime: TZDate, endColumnTime: TZDate) {
function setInnerHeights (line 48) | function setInnerHeights(uiModel: EventUIModel, options: RenderInfoOptio...
function setCroppedEdges (line 79) | function setCroppedEdges(uiModel: EventUIModel, options: RenderInfoOptio...
function getDuplicateLeft (line 90) | function getDuplicateLeft(uiModel: EventUIModel, baseLeft: number) {
function getDuplicateWidth (line 114) | function getDuplicateWidth(uiModel: EventUIModel, baseWidth: number) {
function setDimension (line 128) | function setDimension(uiModel: EventUIModel, options: RenderInfoOptions) {
function getRenderInfoOptions (line 155) | function getRenderInfoOptions(
function setRenderInfo (line 185) | function setRenderInfo({
function setDuplicateEvents (line 228) | function setDuplicateEvents(
function setRenderInfoOfUIModels (line 293) | function setRenderInfoOfUIModels(
FILE: apps/calendar/src/controller/core.ts
function getCollisionGroup (line 17) | function getCollisionGroup<Events extends EventModel | EventUIModel>(
function getLastRowInColumn (line 66) | function getLastRowInColumn(matrix: Array<any[]>, col: number) {
function getMatrices (line 86) | function getMatrices<T extends EventModel | EventUIModel>(
function getEventInDateRangeFilter (line 134) | function getEventInDateRangeFilter(
function positionUIModels (line 158) | function positionUIModels(
function limit (line 199) | function limit(start: TZDate, end: TZDate, uiModel: EventUIModel) {
function limitRenderRange (line 221) | function limitRenderRange(
function convertToUIModel (line 244) | function convertToUIModel(eventCollection: Collection<EventModel>) {
FILE: apps/calendar/src/controller/month.ts
function _isAllday (line 25) | function _isAllday({ model }: EventUIModel) {
function _isNotAllday (line 34) | function _isNotAllday(uiModel: EventUIModel) {
function _weightTopValue (line 42) | function _weightTopValue(uiModel: EventUIModel) {
function _adjustRenderRange (line 56) | function _adjustRenderRange(start: TZDate, end: TZDate, uiModelColl: Col...
function _getAlldayMaxTopIndexAtYMD (line 71) | function _getAlldayMaxTopIndexAtYMD(
function _adjustTimeTopIndex (line 96) | function _adjustTimeTopIndex(idsOfDay: IDS_OF_DAY, uiModelColl: Collecti...
function _stackTimeFromTop (line 121) | function _stackTimeFromTop(idsOfDay: IDS_OF_DAY, uiModelColl: Collection...
function _addMultiDatesInfo (line 157) | function _addMultiDatesInfo(uiModelColl: Collection<EventUIModel>) {
function findByDateRange (line 178) | function findByDateRange(
FILE: apps/calendar/src/controller/times.ts
function getTopPercentByTime (line 13) | function getTopPercentByTime(date: TZDate, start: TZDate, end: TZDate) {
function getTopHeightByTime (line 37) | function getTopHeightByTime(start: TZDate, end: TZDate, minTime: TZDate,...
function setValueByUnit (line 48) | function setValueByUnit(time: TZDate, value: number, unit: TimeUnit) {
function getPrevGridTime (line 74) | function getPrevGridTime(time: TZDate, slot: number, unit: TimeUnit) {
function getNextGridTime (line 99) | function getNextGridTime(time: TZDate, slot: number, unit: TimeUnit) {
FILE: apps/calendar/src/controller/week.ts
function _makeHourRangeFilter (line 39) | function _makeHourRangeFilter(hStart: number, hEnd: number) {
function _makeGetUIModelFuncForTimeView (line 70) | function _makeGetUIModelFuncForTimeView(
function splitEventByDateRange (line 95) | function splitEventByDateRange(
function getUIModelForTimeView (line 134) | function getUIModelForTimeView(
function _addMultiDatesInfo (line 170) | function _addMultiDatesInfo(uiModelColl: Collection<EventUIModel>) {
function getUIModelForAlldayView (line 187) | function getUIModelForAlldayView(
function findByDateRange (line 225) | function findByDateRange(
FILE: apps/calendar/src/factory/calendar.tsx
function isValidViewType (line 11) | function isValidViewType(viewType: string): viewType is ViewType {
class Calendar (line 22) | class Calendar extends CalendarCore {
method constructor (line 23) | constructor(container: Element | string, options: Options = {}) {
method getComponent (line 35) | protected getComponent() {
FILE: apps/calendar/src/factory/calendarCore.spec.tsx
function cleanup (line 26) | function cleanup() {
function MockComponent (line 30) | function MockComponent() {
class MockCalendar (line 44) | class MockCalendar extends CalendarCore {
method getComponent (line 45) | protected getComponent() {
class MockPopupCalendar (line 208) | class MockPopupCalendar extends CalendarCore {
method getComponent (line 209) | protected getComponent() {
function MockMonthView (line 333) | function MockMonthView() {
class MockCalendarMonth (line 339) | class MockCalendarMonth extends CalendarCore {
method getComponent (line 340) | protected getComponent() {
function MockWeekView (line 422) | function MockWeekView() {
class MockCalendarWeek (line 434) | class MockCalendarWeek extends CalendarCore {
method getComponent (line 435) | protected getComponent() {
function MockDayView (line 544) | function MockDayView() {
class MockCalendarDay (line 553) | class MockCalendarDay extends CalendarCore {
method getComponent (line 554) | protected getComponent() {
function MockThemeView (line 634) | function MockThemeView() {
class MockCalendarTheme (line 654) | class MockCalendarTheme extends CalendarCore {
method getComponent (line 655) | protected getComponent() {
function MockOptionsView (line 715) | function MockOptionsView() {
class MockCalendarOptions (line 730) | class MockCalendarOptions extends CalendarCore {
method getComponent (line 731) | protected getComponent() {
function MockCalendarsView (line 795) | function MockCalendarsView() {
class MockCalendarCalendars (line 808) | class MockCalendarCalendars extends CalendarCore {
method getComponent (line 809) | protected getComponent() {
function MockCalendarColorView (line 859) | function MockCalendarColorView() {
class MockCalendarColor (line 872) | class MockCalendarColor extends CalendarCore {
method getComponent (line 873) | protected getComponent() {
function MockMonthMoreViewPopup (line 976) | function MockMonthMoreViewPopup() {
class MockCalendarMonthMoreViewPopup (line 985) | class MockCalendarMonthMoreViewPopup extends Month {
method getComponent (line 986) | protected getComponent() {
class MockCalenderEvent (line 1023) | class MockCalenderEvent extends CalendarCore {
method getComponent (line 1024) | protected getComponent() {
method getComponent (line 1097) | protected getComponent() {
function MockHorizontalEvents (line 1079) | function MockHorizontalEvents() {
class MockCalenderEvent (line 1096) | class MockCalenderEvent extends CalendarCore {
method getComponent (line 1024) | protected getComponent() {
method getComponent (line 1097) | protected getComponent() {
function getMonthDateRange (line 1289) | function getMonthDateRange(renderDate: TZDate, isAlways6Weeks: boolean) {
function MockGridSelectionComponent (line 1379) | function MockGridSelectionComponent() {
class MockGridSelectionCalendar (line 1407) | class MockGridSelectionCalendar extends CalendarCore {
method getComponent (line 1408) | protected getComponent() {
method getComponent (line 1484) | protected getComponent() {
function MockGridSelectionComponent (line 1452) | function MockGridSelectionComponent() {
class MockGridSelectionCalendar (line 1483) | class MockGridSelectionCalendar extends CalendarCore {
method getComponent (line 1408) | protected getComponent() {
method getComponent (line 1484) | protected getComponent() {
FILE: apps/calendar/src/factory/calendarCore.tsx
method constructor (line 186) | constructor(container: string | Element, options: Options = {}) {
method getStoreState (line 210) | protected getStoreState<Group extends keyof CalendarState>(group?: Group) {
method getStoreDispatchers (line 220) | protected getStoreDispatchers<Group extends keyof Dispatchers>(group?: G...
method destroy (line 229) | destroy() {
method calculateMonthRenderDate (line 246) | private calculateMonthRenderDate({
method calculateWeekRenderDate (line 274) | private calculateWeekRenderDate({
method calculateDayRenderDate (line 296) | private calculateDayRenderDate({ renderDate, offset }: { renderDate: TZD...
method move (line 331) | move(offset: number) {
method createEvents (line 396) | createEvents(events: EventObject[]) {
method getEventModel (line 402) | protected getEventModel(eventId: string, calendarId: string) {
method getEvent (line 422) | getEvent(eventId: string, calendarId: string) {
method updateEvent (line 440) | updateEvent(eventId: string, calendarId: string, changes: EventObject) {
method deleteEvent (line 455) | deleteEvent(eventId: string, calendarId: string) {
method setCalendarVisibility (line 474) | setCalendarVisibility(calendarId: string | string[], isVisible: boolean) {
method render (line 493) | render() {
method renderToString (line 511) | renderToString(): string {
method clear (line 525) | clear() {
method scrollToNow (line 541) | scrollToNow(scrollBehavior: ScrollBehaviorOptions = 'auto') {
method calculateRenderRange (line 545) | private calculateRenderRange(renderDate: TZDate) {
method today (line 580) | today() {
method setDate (line 602) | setDate(date: DateType) {
method next (line 622) | next() {
method prev (line 638) | prev() {
method setCalendarColor (line 672) | setCalendarColor(calendarId: string, colorOptions: CalendarColor) {
method changeView (line 693) | changeView(viewName: ViewType) {
method getElement (line 712) | getElement(eventId: string, calendarId: string) {
method setTheme (line 748) | setTheme(theme: DeepPartial<ThemeState>) {
method getOptions (line 759) | getOptions() {
method setOptions (line 775) | setOptions(options: Options) {
method getDate (line 800) | getDate(): TZDate {
method getDateRangeStart (line 811) | getDateRangeStart() {
method getDateRangeEnd (line 820) | getDateRangeEnd() {
method getViewName (line 829) | getViewName(): ViewType {
method setCalendars (line 840) | setCalendars(calendars: CalendarInfo[]) {
method openFormPopup (line 852) | openFormPopup(event: EventObject) {
method clearGridSelections (line 871) | clearGridSelections() {
method fire (line 877) | fire<EventName extends keyof ExternalEventTypes>(
method off (line 886) | off<EventName extends keyof ExternalEventTypes>(
method on (line 895) | on<EventName extends keyof ExternalEventTypes>(
method once (line 904) | once<EventName extends keyof ExternalEventTypes>(
FILE: apps/calendar/src/factory/day.tsx
class Day (line 8) | class Day extends CalendarCore {
method constructor (line 9) | constructor(container: Element, options: Options = {}) {
method getComponent (line 15) | protected getComponent() {
FILE: apps/calendar/src/factory/month.spec.tsx
function setup (line 17) | function setup(options: Options = {}, events: EventObject[] = mockMonthV...
FILE: apps/calendar/src/factory/month.tsx
class Month (line 8) | class Month extends CalendarCore {
method constructor (line 9) | constructor(container: Element, options: Options = {}) {
method getComponent (line 15) | protected getComponent() {
method hideMoreView (line 22) | hideMoreView() {
FILE: apps/calendar/src/factory/week.spec.tsx
function setup (line 14) | function setup(options: Options = {}, events: EventObject[] = mockWeekVi...
FILE: apps/calendar/src/factory/week.tsx
class Week (line 8) | class Week extends CalendarCore {
method constructor (line 9) | constructor(container: Element, options: Options = {}) {
method getComponent (line 15) | protected getComponent() {
FILE: apps/calendar/src/helpers/css.ts
constant CSS_PREFIX (line 7) | const CSS_PREFIX = 'toastui-calendar-';
type ClassNameDictionary (line 9) | interface ClassNameDictionary {
type ClassNameValue (line 13) | type ClassNameValue = string | ClassNameDictionary | undefined | null;
function cls (line 15) | function cls(...args: ClassNameValue[]): string {
function toPercent (line 37) | function toPercent(value: number) {
function toPx (line 41) | function toPx(value: number) {
function extractPercentPx (line 51) | function extractPercentPx(value: string) {
function getEventColors (line 63) | function getEventColors(uiModel: EventUIModel, calendarColor: CalendarCo...
FILE: apps/calendar/src/helpers/dayName.ts
constant DEFAULT_DAY_NAMES (line 7) | const DEFAULT_DAY_NAMES = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sa...
function getDayNames (line 13) | function getDayNames(
FILE: apps/calendar/src/helpers/drag.ts
constant DRAGGING_TYPE_CONSTANTS (line 5) | const DRAGGING_TYPE_CONSTANTS: {
constant DRAGGING_TYPE_CREATORS (line 11) | const DRAGGING_TYPE_CREATORS = {
FILE: apps/calendar/src/helpers/events.ts
type CollisionParam (line 4) | type CollisionParam = {
function hasCollision (line 16) | function hasCollision(start: number, end: number, targetStart: number, t...
function collidesWith (line 24) | function collidesWith({
function isSameEvent (line 53) | function isSameEvent(event: EventModel, eventId: string, calendarId: str...
function isVisibleEvent (line 57) | function isVisibleEvent(event: EventModel) {
FILE: apps/calendar/src/helpers/grid.spec.ts
function createResultMatrix (line 26) | function createResultMatrix({
function assertTimeGridDataRows (line 503) | function assertTimeGridDataRows(
function assertGridPosition (line 589) | function assertGridPosition(results: GridPosition[], expected: GridPosit...
FILE: apps/calendar/src/helpers/grid.ts
constant EVENT_HEIGHT (line 37) | const EVENT_HEIGHT = 22;
constant TOTAL_WIDTH (line 38) | const TOTAL_WIDTH = 100;
function forEachMatrix3d (line 40) | function forEachMatrix3d<T>(matrices: Matrix3d<T>, iteratee: (target: T,...
function isWithinHeight (line 50) | function isWithinHeight(containerHeight: number, eventHeight: number) {
function isExceededHeight (line 54) | function isExceededHeight(containerHeight: number, eventHeight: number) {
function getExceedCount (line 58) | function getExceedCount(
function getGridWidthAndLeftPercentValues (line 68) | function getGridWidthAndLeftPercentValues(
function getWidth (line 101) | function getWidth(widthList: number[], start: number, end: number) {
function getGridDateIndex (line 120) | function getGridDateIndex(date: TZDate, row: TZDate[]) {
function getEventUIModelWithPosition (line 164) | function getEventUIModelWithPosition(
function getRenderedEventUIModels (line 179) | function getRenderedEventUIModels(
function flattenMatrix3d (line 233) | function flattenMatrix3d(matrices: DayGridEventMatrix): EventUIModel[] {
function createDateMatrixOfMonth (line 316) | function createDateMatrixOfMonth(
function getWeekDates (line 359) | function getWeekDates(
function getColumnsData (line 385) | function getColumnsData(
function createTimeGridData (line 419) | function createTimeGridData(
type ContainerPosition (line 454) | interface ContainerPosition {
function getRelativeMousePosition (line 461) | function getRelativeMousePosition(
function getIndexFromPosition (line 468) | function getIndexFromPosition(arrayLength: number, maxRange: number, cur...
function createGridPositionFinder (line 474) | function createGridPositionFinder({
FILE: apps/calendar/src/helpers/gridSelection.ts
type RequiredGridSelectionHookParams (line 14) | type RequiredGridSelectionHookParams = Pick<
type GridSelectionHelper (line 18) | type GridSelectionHelper<
function createSortedGridSelection (line 29) | function createSortedGridSelection(
function calculateTimeGridSelectionByCurrentIndex (line 42) | function calculateTimeGridSelectionByCurrentIndex(
function calculateDayGridMonthSelectionByCurrentIndex (line 107) | function calculateDayGridMonthSelectionByCurrentIndex(
function calculateAlldayGridRowSelectionByCurrentIndex (line 163) | function calculateAlldayGridRowSelectionByCurrentIndex(gridSelection: Gr...
FILE: apps/calendar/src/helpers/popup.ts
function isTopOutOfLayout (line 3) | function isTopOutOfLayout(top: number, layoutRect: Rect, popupRect: Rect...
function isLeftOutOfLayout (line 7) | function isLeftOutOfLayout(left: number, layoutRect: Rect, popupRect: Re...
FILE: apps/calendar/src/helpers/view.ts
function getActivePanels (line 5) | function getActivePanels(
FILE: apps/calendar/src/hooks/calendar/useCalendarById.ts
function useCalendarById (line 5) | function useCalendarById(calendarId: string | null) {
FILE: apps/calendar/src/hooks/calendar/useCalendarColor.ts
function useCalendarColor (line 8) | function useCalendarColor(model?: EventModel): CalendarColor {
FILE: apps/calendar/src/hooks/calendar/useCalendarData.ts
function useCalendarData (line 10) | function useCalendarData(calendar: CalendarData, ...filters: Filter<Even...
FILE: apps/calendar/src/hooks/common/useClickPrevention.ts
function useClickPrevention (line 7) | function useClickPrevention({
FILE: apps/calendar/src/hooks/common/useDOMNode.ts
function useDOMNode (line 4) | function useDOMNode<Node extends HTMLElement>(): [Node | null, RefCallba...
FILE: apps/calendar/src/hooks/common/useDrag.ts
type MouseListener (line 17) | type MouseListener = (e: MouseEvent, dndSlice: DndSlice['dnd']) => void;
type KeyboardListener (line 18) | type KeyboardListener = (e: KeyboardEvent, dndSlice: DndSlice['dnd']) =>...
type DragListeners (line 20) | interface DragListeners {
function isLeftClick (line 33) | function isLeftClick(buttonNum: number) {
function isMouseMoved (line 37) | function isMouseMoved(initX: number, initY: number, x: number, y: number) {
function useDrag (line 44) | function useDrag(
FILE: apps/calendar/src/hooks/common/useDropdownState.ts
function useDropdownState (line 3) | function useDropdownState() {
FILE: apps/calendar/src/hooks/common/useInterval.ts
function useInterval (line 3) | function useInterval(callback: () => void, delay: number | null) {
FILE: apps/calendar/src/hooks/common/useIsMounted.ts
function useIsMounted (line 3) | function useIsMounted(): () => boolean {
FILE: apps/calendar/src/hooks/common/useKeydownEvent.ts
function useKeydownEvent (line 6) | function useKeydownEvent(targetKey: KEY, handler: (event: KeyboardEvent)...
FILE: apps/calendar/src/hooks/common/useTransientUpdate.ts
type Slice (line 7) | type Slice<S> = S extends (state: CalendarState) => infer T ? T : never;
function useTransientUpdate (line 11) | function useTransientUpdate<
FILE: apps/calendar/src/hooks/common/useWhen.ts
function useWhen (line 35) | function useWhen(callback: () => void, condition: boolean) {
FILE: apps/calendar/src/hooks/dayGridMonth/useDayGridMonthEventMove.ts
function useDayGridMonthEventMove (line 13) | function useDayGridMonthEventMove({
FILE: apps/calendar/src/hooks/dayGridMonth/useDayGridMonthEventResize.ts
function getRowPosOfUIModel (line 16) | function getRowPosOfUIModel(uiModel: EventUIModel, dateRow: TZDate[]) {
type EventResizeHookParams (line 26) | interface EventResizeHookParams {
type FilteredUIModelRow (line 34) | type FilteredUIModelRow = [] | [EventUIModel];
function useDayGridMonthEventResize (line 36) | function useDayGridMonthEventResize({
FILE: apps/calendar/src/hooks/dayGridWeek/useAlldayGridRowEventMove.ts
type Params (line 13) | interface Params {
function useAlldayGridRowEventMove (line 18) | function useAlldayGridRowEventMove({ rowStyleInfo, gridPositionFinder }:...
FILE: apps/calendar/src/hooks/dayGridWeek/useAlldayGridRowEventResize.ts
function getEventColIndex (line 14) | function getEventColIndex(uiModel: EventUIModel, row: TZDate[]) {
type Params (line 21) | interface Params {
function useAlldayGridRowEventResize (line 27) | function useAlldayGridRowEventResize({
FILE: apps/calendar/src/hooks/dayGridWeek/useGridRowHeightController.ts
function useGridRowHeightController (line 10) | function useGridRowHeightController(maxTop: number, category: AlldayEven...
FILE: apps/calendar/src/hooks/event/useCurrentPointerPositionInGrid.ts
function useCurrentPointerPositionInGrid (line 9) | function useCurrentPointerPositionInGrid(
FILE: apps/calendar/src/hooks/event/useDraggingEvent.ts
function isEventDraggingType (line 17) | function isEventDraggingType(_itemType: string): _itemType is EventDragg...
function useDraggingEvent (line 28) | function useDraggingEvent(area: EventDraggingArea, behavior: EventDraggi...
FILE: apps/calendar/src/hooks/gridSelection/useGridSelection.spec.tsx
constant CONTAINER_WIDTH (line 21) | const CONTAINER_WIDTH = 70;
constant CONTAINER_HEIGHT (line 22) | const CONTAINER_HEIGHT = 480;
function setup (line 34) | function setup<DateCollection>({
function getGridSelectionState (line 106) | function getGridSelectionState() {
function wrapMockHandler (line 433) | function wrapMockHandler(mockFn: jest.Mock) {
FILE: apps/calendar/src/hooks/gridSelection/useGridSelection.ts
constant GRID_SELECTION_TYPE_MAP (line 22) | const GRID_SELECTION_TYPE_MAP = {
function sortDates (line 28) | function sortDates(a: TZDate, b: TZDate) {
function useGridSelection (line 34) | function useGridSelection<DateCollection>({
FILE: apps/calendar/src/hooks/popup/useFormState.ts
type FormStateActionType (line 5) | enum FormStateActionType {
type FormStateAction (line 16) | type FormStateAction =
type FormStateDispatcher (line 26) | type FormStateDispatcher = (action: FormStateAction) => void;
function formStateReducer (line 37) | function formStateReducer(state: EventObject, action: FormStateAction): ...
function useFormState (line 61) | function useFormState(initCalendarId?: string) {
FILE: apps/calendar/src/hooks/template/useStringOnlyTemplate.ts
function useStringOnlyTemplate (line 6) | function useStringOnlyTemplate({
FILE: apps/calendar/src/hooks/timeGrid/useTimeGridEventMove.spec.tsx
function toMousePosition (line 36) | function toMousePosition(gridX: number, gridY: number) {
FILE: apps/calendar/src/hooks/timeGrid/useTimeGridEventMove.ts
constant THIRTY_MINUTES (line 16) | const THIRTY_MINUTES = 30;
function getCurrentIndexByTime (line 18) | function getCurrentIndexByTime(time: TZDate, hourStart: number) {
function getMovingEventPosition (line 25) | function getMovingEventPosition({
function useTimeGridEventMove (line 70) | function useTimeGridEventMove({
FILE: apps/calendar/src/hooks/timeGrid/useTimeGridEventResize.ts
type FilteredUIModelRow (line 17) | type FilteredUIModelRow = [] | [EventUIModel];
function useTimeGridEventResize (line 19) | function useTimeGridEventResize({
FILE: apps/calendar/src/hooks/timeGrid/useTimeGridScrollSync.ts
function isTimeGridDraggingType (line 8) | function isTimeGridDraggingType(draggingItemType: DraggingTypes | null) {
function useTimeGridScrollSync (line 12) | function useTimeGridScrollSync(scrollArea: HTMLDivElement | null, rowCou...
FILE: apps/calendar/src/hooks/timeGrid/useTimezoneLabelsTop.ts
function timegridHeightSelector (line 8) | function timegridHeightSelector(state: CalendarState) {
function useTimezoneLabelsTop (line 13) | function useTimezoneLabelsTop(timePanel: HTMLDivElement | null): number ...
FILE: apps/calendar/src/hooks/timezone/useEventsWithTimezone.ts
function useEventsWithTimezone (line 13) | function useEventsWithTimezone(events: Collection<EventModel>) {
FILE: apps/calendar/src/hooks/timezone/usePrimaryTimezone.ts
function usePrimaryTimezone (line 8) | function usePrimaryTimezone(): [string, () => TZDate] {
FILE: apps/calendar/src/hooks/timezone/useTZConverter.ts
function useTZConverter (line 8) | function useTZConverter() {
FILE: apps/calendar/src/jest.d.ts
type Matchers (line 5) | interface Matchers<R> {
FILE: apps/calendar/src/model/eventModel.ts
class EventModel (line 16) | class EventModel implements Omit<EventObjectWithDefaultValues, '__cid'> {
method constructor (line 74) | constructor(event: EventObject = {}) {
method init (line 86) | init({
method setAlldayPeriod (line 150) | setAlldayPeriod(start?: DateType, end?: DateType) {
method setTimePeriod (line 173) | setTimePeriod(start?: DateType, end?: DateType) {
method getStarts (line 188) | getStarts() {
method getEnds (line 195) | getEnds() {
method cid (line 202) | cid(): number {
method equals (line 212) | equals(event: EventModel) {
method duration (line 260) | duration(): number {
method valueOf (line 274) | valueOf() {
method collidesWith (line 285) | collidesWith(event: EventModel | EventUIModel, usingTravelTime = true) {
method toEventObject (line 301) | toEventObject(): EventObjectWithDefaultValues {
method getColors (line 333) | getColors() {
function isTimeEvent (line 347) | function isTimeEvent({ model }: EventUIModel) {
FILE: apps/calendar/src/model/eventUIModel.ts
type EventUIProps (line 6) | interface EventUIProps {
class EventUIModel (line 55) | class EventUIModel implements EventUIProps {
method constructor (line 180) | constructor(event: EventModel) {
method getUIProps (line 184) | getUIProps(): EventUIProps {
method setUIProps (line 188) | setUIProps(props: Partial<EventUIProps>) {
method getStarts (line 197) | getStarts(): TZDate {
method getEnds (line 210) | getEnds(): TZDate {
method cid (line 221) | cid() {
method valueOf (line 228) | valueOf(): EventModel {
method duration (line 236) | duration() {
method collidesWith (line 240) | collidesWith(uiModel: EventModel | EventUIModel, usingTravelTime = tru...
method clone (line 277) | clone() {
FILE: apps/calendar/src/selectors/index.ts
function topLevelStateSelector (line 3) | function topLevelStateSelector<State, Group extends keyof State>(
FILE: apps/calendar/src/slices/calendar.ts
type CalendarSlice (line 16) | type CalendarSlice = { calendar: CalendarData };
type UpdateEventParams (line 18) | type UpdateEventParams = { event: EventModel; eventData: EventObject };
type CalendarDispatchers (line 20) | type CalendarDispatchers = {
function createCalendarSlice (line 30) | function createCalendarSlice(calendars: CalendarInfo[] = []): CalendarSl...
function createCalendarDispatchers (line 40) | function createCalendarDispatchers(set: SetState<CalendarStore>): Calend...
FILE: apps/calendar/src/slices/dnd.ts
type DraggingState (line 8) | enum DraggingState {
type DndSlice (line 15) | interface DndSlice {
type DndDispatchers (line 27) | interface DndDispatchers {
function createDndSlice (line 35) | function createDndSlice(): DndSlice {
function createDndDispatchers (line 49) | function createDndDispatchers(set: SetState<CalendarStore>): DndDispatch...
FILE: apps/calendar/src/slices/gridSelection.ts
type GridSelectionSlice (line 6) | type GridSelectionSlice = {
type GridSelectionType (line 17) | type GridSelectionType = Exclude<keyof GridSelectionSlice['gridSelection...
type GridSelectionDispatchers (line 19) | type GridSelectionDispatchers = {
function createGridSelectionSlice (line 25) | function createGridSelectionSlice(): GridSelectionSlice {
function createGridSelectionDispatchers (line 38) | function createGridSelectionDispatchers(
FILE: apps/calendar/src/slices/layout.ts
type WeekGridRows (line 8) | type WeekGridRows = 'milestone' | 'task' | 'allday' | 'time' | string;
type WeekViewLayoutSlice (line 11) | type WeekViewLayoutSlice = {
type UpdateGridRowHeightParams (line 24) | type UpdateGridRowHeightParams = { rowName: WeekGridRows; height: number };
type UpdateGridRowHeightByDiffParams (line 25) | type UpdateGridRowHeightByDiffParams = { rowName: WeekGridRows; diff: nu...
type WeekViewLayoutDispatchers (line 27) | type WeekViewLayoutDispatchers = {
function getRestPanelHeight (line 35) | function getRestPanelHeight(
function createWeekViewLayoutSlice (line 49) | function createWeekViewLayoutSlice(): WeekViewLayoutSlice {
function createWeekViewLayoutDispatchers (line 60) | function createWeekViewLayoutDispatchers(
FILE: apps/calendar/src/slices/options.ts
function initializeCollapseDuplicateEvents (line 24) | function initializeCollapseDuplicateEvents(
function initializeWeekOptions (line 54) | function initializeWeekOptions(weekOptions: Options['week'] = {}): Calen...
function initializeTimezoneOptions (line 76) | function initializeTimezoneOptions(timezoneOptions: Options['timezone'] ...
function initializeMonthOptions (line 83) | function initializeMonthOptions(monthOptions: Options['month'] = {}): Ca...
function initializeGridSelectionOptions (line 102) | function initializeGridSelectionOptions(
type OptionsSlice (line 124) | type OptionsSlice = {
type OptionsDispatchers (line 130) | type OptionsDispatchers = {
function createOptionsSlice (line 135) | function createOptionsSlice(options: Options = {}): OptionsSlice {
function createOptionsDispatchers (line 152) | function createOptionsDispatchers(set: SetState<CalendarStore>): Options...
FILE: apps/calendar/src/slices/popup.ts
type PopupType (line 5) | enum PopupType {
type PopupSlice (line 11) | type PopupSlice = {
type PopupDispatchers (line 19) | type PopupDispatchers = {
function createPopupSlice (line 32) | function createPopupSlice(): PopupSlice {
function createPopupDispatchers (line 42) | function createPopupDispatchers(set: SetState<CalendarStore>): PopupDisp...
FILE: apps/calendar/src/slices/template.ts
type TemplateSlice (line 8) | type TemplateSlice = { template: Template };
type TemplateDispatchers (line 10) | type TemplateDispatchers = {
function createTemplateSlice (line 14) | function createTemplateSlice(templateConfig: TemplateConfig = {}): Templ...
function createTemplateDispatchers (line 23) | function createTemplateDispatchers(set: SetState<CalendarStore>): Templa...
FILE: apps/calendar/src/slices/view.spec.ts
type ViewSliceStore (line 9) | type ViewSliceStore = ViewSlice & ViewDispatchers;
FILE: apps/calendar/src/slices/view.ts
type ViewSlice (line 9) | type ViewSlice = {
type ViewDispatchers (line 16) | type ViewDispatchers = {
function createViewSlice (line 21) | function createViewSlice(initialView: ViewType = 'week'): ViewSlice {
function createViewDispatchers (line 33) | function createViewDispatchers(set: SetState<CalendarStore>): ViewDispat...
FILE: apps/calendar/src/store/index.spec.tsx
type CounterStore (line 12) | type CounterStore = {
type Store (line 97) | type Store = {
FILE: apps/calendar/src/store/index.ts
function createStoreContext (line 18) | function createStoreContext<State extends StateWithActions>() {
FILE: apps/calendar/src/store/internal.ts
function createStore (line 14) | function createStore<State extends StateWithActions>(
FILE: apps/calendar/src/template/default.tsx
constant SIXTY_MINUTES (line 21) | const SIXTY_MINUTES = 60;
method milestone (line 24) | milestone(model: EventObjectWithDefaultValues) {
method milestoneTitle (line 41) | milestoneTitle() {
method task (line 45) | task(model: EventObjectWithDefaultValues) {
method taskTitle (line 49) | taskTitle() {
method alldayTitle (line 53) | alldayTitle() {
method allday (line 57) | allday(model: EventObjectWithDefaultValues) {
method time (line 61) | time(model: EventObjectWithDefaultValues) {
method goingDuration (line 75) | goingDuration(model: EventObjectWithDefaultValues) {
method comingDuration (line 83) | comingDuration(model: EventObjectWithDefaultValues) {
method monthMoreTitleDate (line 91) | monthMoreTitleDate(moreTitle: TemplateMoreTitleDate) {
method monthMoreClose (line 106) | monthMoreClose() {
method monthGridHeader (line 110) | monthGridHeader(model: TemplateMonthGrid) {
method monthGridHeaderExceed (line 117) | monthGridHeaderExceed(hiddenEvents: number) {
method monthGridFooter (line 123) | monthGridFooter(_model: TemplateMonthGrid) {
method monthGridFooterExceed (line 127) | monthGridFooterExceed(_hiddenEvents: number) {
method monthDayName (line 131) | monthDayName(model: TemplateMonthDayName) {
method weekDayName (line 135) | weekDayName(model: TemplateWeekDayName) {
method weekGridFooterExceed (line 147) | weekGridFooterExceed(hiddenEvents: number) {
method collapseBtnTitle (line 151) | collapseBtnTitle() {
method timezoneDisplayLabel (line 157) | timezoneDisplayLabel({ displayLabel, timezoneOffset }: TemplateTimezone) {
method timegridDisplayPrimaryTime (line 169) | timegridDisplayPrimaryTime(props: TemplateNow) {
method timegridDisplayTime (line 175) | timegridDisplayTime(props: TemplateNow) {
method timegridNowIndicatorLabel (line 181) | timegridNowIndicatorLabel(timezone: TemplateNow) {
method popupIsAllday (line 187) | popupIsAllday() {
method popupStateFree (line 191) | popupStateFree() {
method popupStateBusy (line 195) | popupStateBusy() {
method titlePlaceholder (line 199) | titlePlaceholder() {
method locationPlaceholder (line 203) | locationPlaceholder() {
method startDatePlaceholder (line 207) | startDatePlaceholder() {
method endDatePlaceholder (line 211) | endDatePlaceholder() {
method popupSave (line 215) | popupSave() {
method popupUpdate (line 219) | popupUpdate() {
method popupEdit (line 223) | popupEdit() {
method popupDelete (line 227) | popupDelete() {
method popupDetailTitle (line 231) | popupDetailTitle({ title }: EventObjectWithDefaultValues) {
method popupDetailDate (line 235) | popupDetailDate({ isAllday, start, end }: EventObjectWithDefaultValues) {
method popupDetailLocation (line 249) | popupDetailLocation({ location }: EventObjectWithDefaultValues) {
method popupDetailAttendees (line 253) | popupDetailAttendees({ attendees = [] }: EventObjectWithDefaultValues) {
method popupDetailState (line 257) | popupDetailState({ state }: EventObjectWithDefaultValues) {
method popupDetailRecurrenceRule (line 261) | popupDetailRecurrenceRule({ recurrenceRule }: EventObjectWithDefaultValu...
method popupDetailBody (line 265) | popupDetailBody({ body }: EventObjectWithDefaultValues) {
type TemplateName (line 270) | type TemplateName = keyof Template;
FILE: apps/calendar/src/template/index.ts
function registerTemplateConfig (line 11) | function registerTemplateConfig(templateConfig: TemplateConfig = {}): Te...
function getElSize (line 25) | function getElSize(value: number | string, postfix: string, prefix: stri...
function getElLeft (line 40) | function getElLeft(uiModel: EventUIModel, grids: GridUIModel[]) {
function getElWidth (line 50) | function getElWidth(uiModel: EventUIModel, grids: GridUIModel[]) {
function getHhmm (line 70) | function getHhmm(date: TZDate) {
function getCommonWidth (line 79) | function getCommonWidth(width: number | string) {
function getGridLeft (line 89) | function getGridLeft(uiModel: EventUIModel, grids: GridUIModel[]) {
function getGridWidth (line 99) | function getGridWidth(uiModel: EventUIModel, grids: GridUIModel[]) {
function getTimeEventBlock (line 108) | function getTimeEventBlock(uiModel: EventUIModel) {
function getMonthEventBlock (line 117) | function getMonthEventBlock(
function getHolidayClass (line 131) | function getHolidayClass(day: number) {
function getRight (line 143) | function getRight(a: number, b: number) {
FILE: apps/calendar/src/test/helpers.ts
function createDate (line 3) | function createDate(y: number, M: number, d: number): TZDate {
FILE: apps/calendar/src/test/matchers.ts
function pickTitle (line 8) | function pickTitle(matrix: EventUIModel[]) {
function fail (line 23) | function fail(message: string) {
function titleComparator (line 30) | function titleComparator(uiModel: EventUIModel, title: string | number) {
function topComparator (line 34) | function topComparator(uiModel: EventUIModel, top: string | number) {
function getMatcher (line 38) | function getMatcher(comparator: (uiModel: EventUIModel, value: string | ...
method toEqualUIModelByTitle (line 96) | toEqualUIModelByTitle(actual: Record<string, EventModel[]>, expected: Re...
method toBeSameDate (line 123) | toBeSameDate(actual: number | string | TZDate | Date, expected: number |...
FILE: apps/calendar/src/test/testIds.ts
constant TEST_IDS (line 1) | const TEST_IDS = {
FILE: apps/calendar/src/test/utils.tsx
function render (line 24) | function render(
function renderHook (line 47) | function renderHook<R, P>(
function dragAndDrop (line 70) | function dragAndDrop({
function hasDesiredStartTime (line 89) | function hasDesiredStartTime(el: HTMLElement, startTimeStr: FormattedTim...
FILE: apps/calendar/src/theme/common.ts
function createCommonTheme (line 8) | function createCommonTheme(commonTheme: DeepPartial<CommonTheme> = {}): {
FILE: apps/calendar/src/theme/dispatch.spec.tsx
function CommonThemeComponent (line 18) | function CommonThemeComponent() {
function WeekThemeComponent (line 98) | function WeekThemeComponent() {
function MonthThemeComponent (line 184) | function MonthThemeComponent() {
function ThemeComponent (line 275) | function ThemeComponent() {
FILE: apps/calendar/src/theme/dispatch.ts
function createThemeDispatch (line 8) | function createThemeDispatch(set: SetState<ThemeStore>): ThemeDispatchers {
FILE: apps/calendar/src/theme/month.ts
function createMonthTheme (line 8) | function createMonthTheme(monthTheme: DeepPartial<MonthTheme> = {}): {
FILE: apps/calendar/src/theme/week.ts
function createWeekTheme (line 8) | function createWeekTheme(weekTheme: DeepPartial<WeekTheme> = {}): {
FILE: apps/calendar/src/time/date.ts
function getTZOffsetMSDifference (line 11) | function getTZOffsetMSDifference(offset: number) {
class TZDate (line 23) | class TZDate {
method constructor (line 28) | constructor(...args: any[]) {
method toString (line 40) | toString() {
method addFullYear (line 49) | addFullYear(y: number): TZDate {
method addMonth (line 60) | addMonth(m: number): TZDate {
method addDate (line 71) | addDate(d: number): TZDate {
method addHours (line 82) | addHours(h: number): TZDate {
method addMinutes (line 93) | addMinutes(M: number): TZDate {
method addSeconds (line 104) | addSeconds(s: number): TZDate {
method addMilliseconds (line 115) | addMilliseconds(ms: number): TZDate {
method setWithRaw (line 133) | setWithRaw(y: number, m: number, d: number, h: number, M: number, s: n...
method toDate (line 144) | toDate(): Date {
method valueOf (line 152) | valueOf(): number {
method getTimezoneOffset (line 160) | getTimezoneOffset() {
method getTime (line 169) | getTime(): number {
method getFullYear (line 177) | getFullYear(): number {
method getMonth (line 185) | getMonth(): number {
method getDate (line 193) | getDate(): number {
method getHours (line 201) | getHours(): number {
method getMinutes (line 209) | getMinutes(): number {
method getSeconds (line 217) | getSeconds(): number {
method getMilliseconds (line 225) | getMilliseconds(): number {
method getDay (line 233) | getDay(): number {
method setTime (line 242) | setTime(t: number): number {
method setFullYear (line 253) | setFullYear(y: number, m = this.getMonth(), d = this.getDate()): number {
method setMonth (line 263) | setMonth(m: number, d = this.getDate()): number {
method setDate (line 272) | setDate(d: number): number {
method setHours (line 284) | setHours(
method setMinutes (line 300) | setMinutes(M: number, s = this.getSeconds(), ms = this.getMilliseconds...
method setSeconds (line 310) | setSeconds(s: number, ms = this.getMilliseconds()): number {
method setMilliseconds (line 319) | setMilliseconds(ms: number): number {
method tz (line 328) | tz(tzValue: string | 'Local' | number) {
method local (line 351) | local(tzValue?: string | number) {
FILE: apps/calendar/src/time/datetime.ts
type Day (line 11) | enum Day {
constant WEEK_DAYS (line 21) | const WEEK_DAYS = 7;
type ReduceIteratee (line 23) | interface ReduceIteratee {
function leadingZero (line 42) | function leadingZero(number: number, length: number): string {
function getHourForMeridiem (line 57) | function getHourForMeridiem(date: TZDate) {
method YYYYMMDD (line 72) | YYYYMMDD(date: TZDate): string {
method YYYY (line 79) | YYYY(date: TZDate): string {
method MM (line 82) | MM(date: TZDate): string {
method DD (line 85) | DD(date: TZDate): string {
method hh (line 100) | hh(date: TZDate): string {
method tt (line 105) | tt(date: TZDate): string {
constant MS_PER_DAY (line 112) | const MS_PER_DAY = 86400000;
constant MS_PER_HOUR (line 113) | const MS_PER_HOUR = 3600000;
constant MS_PER_MINUTES (line 114) | const MS_PER_MINUTES = 60000;
constant MS_EVENT_MIN_DURATION (line 119) | const MS_EVENT_MIN_DURATION = 20 * MS_PER_MINUTES;
constant MS_PER_THIRTY_MINUTES (line 120) | const MS_PER_THIRTY_MINUTES = 30 * 60 * 1000;
constant SIXTY_SECONDS (line 121) | const SIXTY_SECONDS = 60;
function toFormat (line 133) | function toFormat(date: TZDate, strFormat: string): string {
function convMilliseconds (line 146) | function convMilliseconds(type: TimeUnit, value: number, iteratee: Reduc...
function millisecondsFrom (line 164) | function millisecondsFrom(type: TimeUnit, value: number): number {
function toStartOfDay (line 186) | function toStartOfDay(date?: number | TZDate | Date): TZDate {
function makeDateRange (line 196) | function makeDateRange(startDate: TZDate, endDate: TZDate, step: number)...
function clone (line 215) | function clone(date: TZDate): TZDate {
function compare (line 226) | function compare(d1: TZDate, d2: TZDate): number {
function isSameYear (line 240) | function isSameYear(d1: TZDate, d2: TZDate): boolean {
function isSameMonth (line 244) | function isSameMonth(d1: TZDate, d2: TZDate): boolean {
function isSameDate (line 248) | function isSameDate(d1: TZDate, d2: TZDate): boolean {
function max (line 252) | function max(d1: TZDate, d2: TZDate): TZDate {
function min (line 256) | function min(d1: TZDate, d2: TZDate): TZDate {
function parse (line 270) | function parse(str: string, fixMonth = -1): TZDate {
function toEndOfDay (line 312) | function toEndOfDay(date?: number | TZDate): TZDate {
function isWeekend (line 319) | function isWeekend(day: Day): boolean {
function isSunday (line 323) | function isSunday(day: Day): boolean {
function isSaturday (line 327) | function isSaturday(day: Day): boolean {
function isBetweenWithDate (line 334) | function isBetweenWithDate(d: TZDate, d1: TZDate, d2: TZDate): boolean {
function toStartOfMonth (line 343) | function toStartOfMonth(date: TZDate): TZDate {
function toStartOfYear (line 352) | function toStartOfYear(d: TZDate): TZDate {
function toEndOfMonth (line 356) | function toEndOfMonth(date: TZDate): TZDate {
function getRowStyleInfo (line 369) | function getRowStyleInfo(
function addMilliseconds (line 418) | function addMilliseconds(d: TZDate, step: number) {
function addMinutes (line 425) | function addMinutes(d: TZDate, step: number) {
function addHours (line 432) | function addHours(d: TZDate, step: number) {
function setTimeStrToDate (line 439) | function setTimeStrToDate(d: TZDate, timeStr: FormattedTimeString) {
function addDate (line 446) | function addDate(d: TZDate, step: number) {
function subtractDate (line 453) | function subtractDate(d: TZDate, steps: number) {
function addMonths (line 465) | function addMonths(d: TZDate, step = 1) {
function addYear (line 484) | function addYear(d: TZDate, step: number) {
function getDateDifference (line 491) | function getDateDifference(d1: TZDate, d2: TZDate) {
FILE: apps/calendar/src/time/timezone.spec.ts
function startMockingTimezone (line 18) | function startMockingTimezone(timezoneName: TimeZone, initialDate: strin...
function finishMockingTimezone (line 26) | function finishMockingTimezone() {
FILE: apps/calendar/src/time/timezone.ts
function setDateConstructor (line 11) | function setDateConstructor(constructor: TuiDateConstructor) {
function date (line 15) | function date(...args: any[]) {
function getLocalTimezoneOffset (line 20) | function getLocalTimezoneOffset() {
function calculateTimezoneOffset (line 29) | function calculateTimezoneOffset(timezoneName: string, targetDate: TZDat...
function isUsingDST (line 48) | function isUsingDST(targetDate: TZDate, timezoneName?: string) {
function isIntlDateTimeFormatSupported (line 74) | function isIntlDateTimeFormatSupported() {
function validateIANATimezoneName (line 82) | function validateIANATimezoneName(timezoneName: string) {
function getDateTimeFormat (line 100) | function getDateTimeFormat(timezoneName: string) {
type TokenizeTarget (line 120) | type TokenizeTarget = Extract<
type TokenizeResult (line 133) | type TokenizeResult = [number, number, number, number, number, number];
function tokenizeTZDate (line 134) | function tokenizeTZDate(tzDate: TZDate, timezoneName: string): TokenizeR...
function tokenToUtcDate (line 149) | function tokenToUtcDate(token: TokenizeResult) {
FILE: apps/calendar/src/tui-code-snippet.d.ts
type Browser (line 50) | interface Browser {
class CustomEvents (line 65) | class CustomEvents {
FILE: apps/calendar/src/types/components/common.ts
type PropsWithChildren (line 3) | type PropsWithChildren<Props = {}> = Props & { children?: ComponentChild...
type StyleProp (line 5) | type StyleProp = h.JSX.CSSProperties;
type FormEvent (line 7) | type FormEvent = h.JSX.TargetedEvent<HTMLFormElement, Event>;
type CalendarViewType (line 9) | type CalendarViewType = 'week' | 'month';
FILE: apps/calendar/src/types/components/gridSelection.ts
type GridSelectionData (line 1) | interface GridSelectionData {
type GridSelectionDataByRow (line 8) | interface GridSelectionDataByRow {
type TimeGridSelectionDataByCol (line 13) | interface TimeGridSelectionDataByCol {
FILE: apps/calendar/src/types/drag.ts
type EventDraggingArea (line 3) | type EventDraggingArea = 'dayGrid' | 'timeGrid';
type EventDraggingBehavior (line 5) | type EventDraggingBehavior = 'move' | 'resize';
type EventDragging (line 7) | type EventDragging<EventId extends string = any> =
type GridSelectionDragging (line 10) | type GridSelectionDragging = `gridSelection/${GridSelectionType}`;
type DraggingTypes (line 12) | type DraggingTypes<EventId extends string = any> =
FILE: apps/calendar/src/types/eventBus.ts
type AnyFunc (line 3) | type AnyFunc = (...args: any[]) => any;
type SelectDateTimeInfo (line 5) | interface SelectDateTimeInfo {
type UpdatedEventInfo (line 13) | interface UpdatedEventInfo {
type DayNameInfo (line 18) | interface DayNameInfo {
type EventInfo (line 22) | interface EventInfo {
type MoreEventsButton (line 27) | interface MoreEventsButton {
type ScrollBehaviorOptions (line 32) | type ScrollBehaviorOptions = ScrollToOptions['behavior'];
type ExternalEventTypes (line 34) | type ExternalEventTypes = {
type InternalEventTypes (line 47) | type InternalEventTypes = {
FILE: apps/calendar/src/types/events.ts
type Matrix (line 11) | type Matrix<T> = T[][];
type Matrix3d (line 12) | type Matrix3d<T> = Matrix<T>[];
type CollisionGroup (line 13) | type CollisionGroup = Matrix<number>;
type DayGridEventMatrix (line 15) | type DayGridEventMatrix = Matrix3d<EventUIModel>;
type TimeGridEventMatrix (line 16) | type TimeGridEventMatrix = Record<string, Matrix3d<EventUIModel>>;
type EventModelMap (line 18) | type EventModelMap = {
type EventGroupMap (line 25) | type EventGroupMap = Record<keyof EventModelMap, DayGridEventMatrix | Ti...
type DateType (line 27) | type DateType = Date | string | number | TZDate;
type IDS_OF_DAY (line 29) | type IDS_OF_DAY = Record<string, number[]>;
type CalendarData (line 31) | interface CalendarData {
type EventCategory (line 37) | type EventCategory = 'milestone' | 'task' | 'allday' | 'time';
type EventState (line 39) | type EventState = 'Busy' | 'Free';
type EventObjectWithDefaultValues (line 41) | type EventObjectWithDefaultValues = MarkOptional<
type EventObject (line 50) | interface EventObject {
type BooleanKeyOfEventObject (line 182) | type BooleanKeyOfEventObject =
type TimeUnit (line 190) | type TimeUnit = 'second' | 'minute' | 'hour' | 'date' | 'month' | 'year';
FILE: apps/calendar/src/types/grid.ts
type GridUIModel (line 7) | interface GridUIModel {
type GridPosition (line 13) | interface GridPosition {
type CommonGridColumn (line 18) | interface CommonGridColumn {
type TimeGridRow (line 24) | interface TimeGridRow {
type TimeGridData (line 31) | interface TimeGridData {
type GridPositionFinder (line 36) | type GridPositionFinder = (mousePosition: ClientMousePosition) => GridPo...
FILE: apps/calendar/src/types/mouse.ts
type Coordinates (line 6) | interface Coordinates {
type ClientMousePosition (line 11) | type ClientMousePosition = Pick<MouseEvent, 'clientX' | 'clientY'>;
FILE: apps/calendar/src/types/options.ts
type EventView (line 9) | type EventView = 'allday' | 'time';
type TaskView (line 10) | type TaskView = 'milestone' | 'task';
type CollapseDuplicateEventsOptions (line 12) | interface CollapseDuplicateEventsOptions {
type WeekOptions (line 20) | interface WeekOptions {
type MonthOptions (line 35) | interface MonthOptions {
type GridSelectionOptions (line 45) | interface GridSelectionOptions {
type TimezoneConfig (line 50) | interface TimezoneConfig {
type TimezoneOptions (line 56) | interface TimezoneOptions {
type CalendarColor (line 61) | interface CalendarColor {
type CalendarInfo (line 68) | interface CalendarInfo extends CalendarColor {
type ViewType (line 73) | type ViewType = 'month' | 'week' | 'day';
type Options (line 75) | interface Options {
type ViewInfoUserInput (line 91) | interface ViewInfoUserInput {
type ViewListMap (line 98) | type ViewListMap = {
FILE: apps/calendar/src/types/panel.ts
type AlldayEventCategory (line 1) | type AlldayEventCategory = 'milestone' | 'allday' | 'task';
type PanelType (line 3) | type PanelType = 'daygrid' | 'timegrid';
type Panel (line 5) | interface Panel {
FILE: apps/calendar/src/types/store.ts
type CalendarMonthOptions (line 16) | type CalendarMonthOptions = Required<MonthOptions>;
type CalendarWeekOptions (line 17) | type CalendarWeekOptions = Required<WeekOptions>;
type Rect (line 19) | type Rect = Pick<DOMRect, 'top' | 'left' | 'width' | 'height'>;
type BasePopupParam (line 21) | interface BasePopupParam {
type PopupParamMap (line 27) | type PopupParamMap = {
type SeeMorePopupParam (line 33) | interface SeeMorePopupParam extends BasePopupParam {
type EventFormPopupParam (line 38) | interface EventFormPopupParam extends BasePopupParam {
type EventDetailPopupParam (line 50) | interface EventDetailPopupParam extends BasePopupParam {
type PopupPosition (line 55) | type PopupPosition = {
type PopupArrowPointPosition (line 62) | type PopupArrowPointPosition = {
type StateWithActions (line 67) | type StateWithActions = Record<string, any>;
type PartialStateCreator (line 68) | type PartialStateCreator<State extends StateWithActions, Key extends key...
type StateSelector (line 71) | type StateSelector<State extends StateWithActions, SelectedState> = (
type EqualityChecker (line 74) | type EqualityChecker<State> = (state: State, newState: State) => boolean;
type StateListener (line 75) | type StateListener<State> = (state: State, previousState: State) => void;
type StateSliceListener (line 76) | type StateSliceListener<StateSlice> = (slice: StateSlice, previousSlice:...
type SetState (line 77) | type SetState<State extends StateWithActions> = <Key extends keyof Omit<...
type GetState (line 80) | type GetState<State extends StateWithActions> = () => State;
type Unsubscribe (line 81) | type Unsubscribe = () => void;
type Subscribe (line 83) | interface Subscribe<State extends StateWithActions> {
type InternalStoreAPI (line 93) | interface InternalStoreAPI<State extends StateWithActions> {
type StoreCreator (line 100) | type StoreCreator<State extends StateWithActions> = (
type CalendarState (line 106) | type CalendarState = OptionsSlice &
type Dispatchers (line 115) | type Dispatchers = {
type CalendarStore (line 126) | type CalendarStore = CalendarState & {
FILE: apps/calendar/src/types/template.ts
type TemplateTimeGridHourLabel (line 7) | interface TemplateTimeGridHourLabel {
type TemplateNow (line 13) | interface TemplateNow {
type TemplateMonthGrid (line 19) | interface TemplateMonthGrid {
type TemplateMoreTitleDate (line 29) | interface TemplateMoreTitleDate {
type TemplateWeekDayName (line 35) | interface TemplateWeekDayName {
type TemplateMonthDayName (line 44) | interface TemplateMonthDayName {
type TemplateTimezone (line 53) | type TemplateTimezone =
type TemplateReturnType (line 57) | type TemplateReturnType = string | VNode<{ className: string }>;
type Template (line 59) | interface Template {
type TemplateConfig (line 103) | type TemplateConfig = Partial<Template>;
FILE: apps/calendar/src/types/theme.ts
type CommonTheme (line 3) | type CommonTheme = {
type WeekDayNameTheme (line 16) | type WeekDayNameTheme = {
type MonthDayNameTheme (line 23) | type MonthDayNameTheme = {
type DayGridTheme (line 28) | type DayGridTheme = {
type DayGridLeftTheme (line 33) | type DayGridLeftTheme = {
type TimeGridLeftTheme (line 39) | type TimeGridLeftTheme = {
type WeekTheme (line 45) | type WeekTheme = {
type MonthTheme (line 68) | type MonthTheme = {
type ThemeState (line 89) | type ThemeState = {
type ThemeDispatchers (line 95) | type ThemeDispatchers = {
type ThemeStore (line 102) | type ThemeStore = ThemeState & {
FILE: apps/calendar/src/types/time/datetime.ts
type RawDate (line 3) | type RawDate = {
type CellStyle (line 13) | interface CellStyle {
type CellInfo (line 18) | interface CellInfo extends CellStyle {
type HoursString (line 22) | type HoursString =
type FormattedTimeString (line 25) | type FormattedTimeString = `${HoursString}:${0 | 3}0`;
FILE: apps/calendar/src/types/util.ts
type Element (line 1) | interface Element {
type MouseEventListener (line 5) | type MouseEventListener = (e: MouseEvent) => void;
type KeyboardEventListener (line 6) | type KeyboardEventListener = (e: KeyboardEvent) => void;
FILE: apps/calendar/src/utils/array.spec.ts
type Item (line 156) | interface Item {
function compare (line 197) | function compare(a: Item, b: Item) {
FILE: apps/calendar/src/utils/array.ts
function compareBooleansASC (line 5) | function compareBooleansASC(a: boolean, b: boolean) {
function compareNumbersASC (line 13) | function compareNumbersASC(a: any, b: any) {
function compareStringsASC (line 17) | function compareStringsASC(_a: any, _b: any) {
function compareEventsASC (line 29) | function compareEventsASC(a: EventModel | EventUIModel, b: EventModel | ...
function bsearch (line 60) | function bsearch(
function first (line 103) | function first<T>(array: Array<T>) {
function last (line 107) | function last<T>(array: Array<T>) {
function findLastIndex (line 111) | function findLastIndex<T>(array: T[], predicate: (value: T) => boolean):...
function fill (line 121) | function fill<T>(length: number, value: T): T[] {
FILE: apps/calendar/src/utils/collection.spec.ts
type Item (line 3) | type Item = Record<string, any>;
function filter1 (line 200) | function filter1(item: Item) {
function filter2 (line 204) | function filter2(item: Item) {
function filter3 (line 208) | function filter3(item: Item) {
function filter1 (line 242) | function filter1(item: Item) {
function filter2 (line 246) | function filter2(item: Item) {
function filter1 (line 280) | function filter1(item: Item) {
function filter2 (line 283) | function filter2(item: Item) {
function filter3 (line 286) | function filter3(item: Item) {
function filter1 (line 304) | function filter1(item: Item) {
function filter2 (line 307) | function filter2(item: Item) {
function filter3 (line 310) | function filter3(item: Item) {
method no (line 337) | no() {
method no (line 347) | no() {
method no (line 357) | no() {
FILE: apps/calendar/src/utils/collection.ts
type ItemID (line 3) | type ItemID = string | number;
type Item (line 4) | type Item = {
type Filter (line 9) | type Filter<ItemType> = (item: ItemType) => boolean;
class Collection (line 19) | class Collection<ItemType extends Item> {
method constructor (line 22) | constructor(getItemIDFn?: (item: ItemType) => ItemID) {
method and (line 33) | static and<ItemType>(...filterFns: Array<Filter<ItemType>>) {
method or (line 52) | static or<ItemType>(...filterFns: Array<Filter<ItemType>>) {
method getItemID (line 75) | getItemID(item: ItemType): ItemID {
method getFirstItem (line 79) | getFirstItem(): ItemType | null {
method add (line 89) | add(...items: ItemType[]): Collection<ItemType> {
method remove (line 103) | remove(...items: Array<ItemType | ItemID>): ItemType[] | ItemType {
method has (line 125) | has(item: ItemType | ItemID): boolean {
method get (line 131) | get(item: ItemType | ItemID): ItemType | null {
method doWhenHas (line 142) | doWhenHas(id: ItemID, callback: (item: ItemType) => void) {
method filter (line 173) | filter(filterFn: Filter<ItemType>): Collection<ItemType> {
method groupBy (line 208) | groupBy(
method find (line 232) | find(findFn: Filter<ItemType>): ItemType | null {
method sort (line 253) | sort(compareFn: (a: ItemType, b: ItemType) => number): ItemType[] {
method each (line 263) | each(iteratee: (item: ItemType, key: keyof ItemType) => boolean | void) {
method clear (line 279) | clear() {
method toArray (line 287) | toArray(): ItemType[] {
method size (line 291) | get size(): number {
FILE: apps/calendar/src/utils/dom.ts
constant CSS_AUTO_REGEX (line 4) | const CSS_AUTO_REGEX = /^auto$|^$|%/;
function getStyle (line 6) | function getStyle(el: HTMLElement, style: keyof CSSStyleDeclaration) {
function getPosition (line 18) | function getPosition(el: HTMLElement) {
type SizeValue (line 35) | type SizeValue = 'auto' | string | null;
function invalidateSizeValue (line 37) | function invalidateSizeValue(value: SizeValue) {
function getSize (line 45) | function getSize(el: HTMLElement): { width: number; height: number } {
function isOverlapped (line 64) | function isOverlapped(el1: Element, el2: Element) {
function matches (line 83) | function matches(element: Node & ParentNode, selector: string) {
function closest (line 87) | function closest(element: HTMLElement, selector: string) {
function stripTags (line 105) | function stripTags(str: string) {
FILE: apps/calendar/src/utils/error.ts
class InvalidTimezoneNameError (line 15) | class InvalidTimezoneNameError extends Error {
method constructor (line 16) | constructor(timezoneName: string) {
class InvalidDateTimeFormatError (line 22) | class InvalidDateTimeFormatError extends Error {
method constructor (line 23) | constructor(dateTimeString: string) {
class InvalidViewTypeError (line 29) | class InvalidViewTypeError extends Error {
method constructor (line 30) | constructor(viewType: string) {
FILE: apps/calendar/src/utils/eventBus.ts
type EventBus (line 5) | interface EventBus<
class EventBusImpl (line 28) | class EventBusImpl<
method on (line 36) | on<EventName extends keyof EventTypes>(eventName: EventName, handler: ...
method off (line 42) | off<EventName extends keyof EventTypes>(eventName?: EventName, handler...
method fire (line 48) | fire<EventName extends keyof EventTypes>(
method once (line 57) | once<EventName extends keyof EventTypes>(eventName: EventName, handler...
FILE: apps/calendar/src/utils/keyboard.ts
function isKeyPressed (line 4) | function isKeyPressed(e: KeyboardEvent, key: KEY) {
FILE: apps/calendar/src/utils/math.ts
function limit (line 1) | function limit(value: number, minArr: number[], maxArr: number[]) {
function ratio (line 12) | function ratio(a: number, b: number, y: number) {
function isBetween (line 16) | function isBetween(value: number, min: number, max: number) {
FILE: apps/calendar/src/utils/object.spec.ts
type Expected (line 65) | type Expected = {
FILE: apps/calendar/src/utils/object.ts
function pick (line 6) | function pick<T extends object, K extends keyof T>(obj: T, ...propNames:...
function clone (line 23) | function clone<T extends object>(source: T): T {
function mergeObject (line 38) | function mergeObject<Target, Source extends DeepPartial<Target>>(
FILE: apps/calendar/src/utils/preact.ts
function passConditionalProp (line 6) | function passConditionalProp<P>(condition: boolean, prop: P) {
FILE: apps/calendar/src/utils/requestTimeout.ts
function requestTimeout (line 4) | function requestTimeout(fn: Function, delay: number, registerCancel: Fun...
FILE: apps/calendar/src/utils/sanitizer.ts
constant TEMP_TARGET_ATTRIBUTE (line 4) | const TEMP_TARGET_ATTRIBUTE = 'data-target-temp';
function addAttributeHooks (line 10) | function addAttributeHooks() {
function removeAttributeHooks (line 40) | function removeAttributeHooks() {
function sanitize (line 47) | function sanitize(str: string) {
FILE: apps/calendar/src/utils/stamp.ts
type StampObj (line 3) | interface StampObj extends Record<string, any> {
function idGenerator (line 8) | function idGenerator() {
function stamp (line 26) | function stamp(obj: StampObj): number {
function hasStamp (line 35) | function hasStamp(obj: StampObj): boolean {
FILE: apps/calendar/src/utils/string.ts
function capitalize (line 1) | function capitalize(str: string) {
FILE: apps/calendar/src/utils/type.ts
function isNil (line 3) | function isNil(value: unknown): value is null | undefined {
function isPresent (line 7) | function isPresent<T>(value: T | null | undefined): value is T {
function isFunction (line 11) | function isFunction(value: unknown): value is Function {
FILE: apps/calendar/stories/column.stories.tsx
function Wrapper (line 17) | function Wrapper({ children }: PropsWithChildren) {
function getTimeGridData (line 25) | function getTimeGridData() {
FILE: apps/calendar/stories/dayView.stories.tsx
function createTimeGridEvents (line 15) | function createTimeGridEvents() {
FILE: apps/calendar/stories/e2e/week.stories.tsx
method alldayTitle (line 277) | alldayTitle() {
method taskTitle (line 281) | taskTitle() {
FILE: apps/calendar/stories/eventDetailPopup.stories.tsx
function Wrapper (line 21) | function Wrapper({ children, event, eventRect }: PropsWithChildren<Event...
FILE: apps/calendar/stories/eventFormPopup.stories.tsx
type EventFormPopupStoryProps (line 21) | interface EventFormPopupStoryProps extends EventFormPopupParam {
function Wrapper (line 25) | function Wrapper({
FILE: apps/calendar/stories/gridHeader.stories.tsx
type DayNamesStory (line 14) | interface DayNamesStory {
FILE: apps/calendar/stories/helper/event.ts
function createEventModels (line 6) | function createEventModels(data: EventObject[]): EventUIModel[] {
FILE: apps/calendar/stories/mocks/mockMonthViewEvents.ts
constant DAYS_OF_WEEK (line 6) | const DAYS_OF_WEEK = 7;
function createMockMonthViewEvents (line 8) | function createMockMonthViewEvents(baseDate?: string): MockedMonthViewEv...
constant MOCK_MONTH_VIEW_BASE_DATE (line 67) | const MOCK_MONTH_VIEW_BASE_DATE = '2022-04-01';
FILE: apps/calendar/stories/mocks/types.ts
type MockedWeekViewEvents (line 5) | type MockedWeekViewEvents = Required<
type MockedMonthViewEvents (line 15) | type MockedMonthViewEvents = Omit<MockedWeekViewEvents, 'isAllday' | 'ca...
FILE: apps/calendar/stories/timegrid.stories.tsx
function toThisWeek (line 21) | function toThisWeek(date: TZDate) {
function getNormalEvents (line 31) | function getNormalEvents() {
function getEvents (line 44) | function getEvents() {
function getTimeGridData (line 86) | function getTimeGridData() {
type TimeGridProps (line 92) | type TimeGridProps = ComponentProps<typeof TimeGrid>;
FILE: apps/calendar/stories/util/calendarExample.tsx
type Props (line 10) | interface Props {
type CalendarExampleStory (line 16) | type CalendarExampleStory = Story<Props>;
function CalendarExample (line 18) | function CalendarExample({ options, containerHeight = 600, onInit }: Pro...
FILE: apps/calendar/stories/util/mockCalendarDates.ts
function getMockCurrentDate (line 5) | function getMockCurrentDate() {
function getWeekDates (line 15) | function getWeekDates() {
function getWeekendDates (line 21) | function getWeekendDates() {
FILE: apps/calendar/stories/util/mockCalendars.ts
function addCalendar (line 5) | function addCalendar(calendar: CalendarInfo) {
function initialize (line 19) | function initialize() {
FILE: apps/calendar/stories/util/providerWrapper.tsx
type Props (line 20) | type Props = {
function ProviderWrapper (line 25) | function ProviderWrapper({
FILE: apps/calendar/stories/util/randomEvents.ts
constant EVENT_CATEGORY (line 14) | const EVENT_CATEGORY: EventCategory[] = ['milestone', 'task'];
function createTime (line 17) | function createTime(event: EventObject, renderStart: TZDate, renderEnd: ...
function createNames (line 56) | function createNames() {
function createRandomEvent (line 67) | function createRandomEvent(calendar: CalendarInfo, renderStart: TZDate, ...
function createRandomEvents (line 117) | function createRandomEvents(
function createRandomEventModelsForMonth (line 137) | function createRandomEventModelsForMonth(length = defaultEventCount.mont...
FILE: apps/calendar/stories/weekView.stories.tsx
function createTimeGridEvents (line 15) | function createTimeGridEvents() {
FILE: apps/calendar/webpack.config.js
function getBabelConfig (line 17) | function getBabelConfig(isIE11) {
FILE: apps/react-calendar/example/app.tsx
type ViewType (line 13) | type ViewType = 'month' | 'week' | 'day';
function App (line 31) | function App({ view }: { view: ViewType }) {
FILE: apps/react-calendar/example/utils.ts
function clone (line 3) | function clone(date: TZDate): TZDate {
function addHours (line 7) | function addHours(d: TZDate, step: number) {
function addDate (line 14) | function addDate(d: TZDate, step: number) {
function subtractDate (line 21) | function subtractDate(d: TZDate, steps: number) {
FILE: apps/react-calendar/src/index.tsx
type ReactCalendarOptions (line 7) | type ReactCalendarOptions = Omit<Options, 'defaultView'>;
type CalendarView (line 8) | type CalendarView = Required<Options>['defaultView'];
type CalendarExternalEventNames (line 10) | type CalendarExternalEventNames = Extract<keyof ExternalEventTypes, stri...
type ReactCalendarEventNames (line 11) | type ReactCalendarEventNames = `on${Capitalize<CalendarExternalEventName...
type ReactCalendarEventHandler (line 12) | type ReactCalendarEventHandler = ExternalEventTypes[CalendarExternalEven...
type ReactCalendarExternalEvents (line 13) | type ReactCalendarExternalEvents = {
type Props (line 17) | type Props = ReactCalendarOptions & {
class ToastUIReactCalendar (line 48) | class ToastUIReactCalendar extends React.Component<Props> {
method componentDidMount (line 58) | componentDidMount() {
method shouldComponentUpdate (line 72) | shouldComponentUpdate(nextProps: Readonly<Props>) {
method componentWillUnmount (line 118) | componentWillUnmount() {
method setCalendars (line 122) | setCalendars(calendars?: Options['calendars']) {
method setEvents (line 128) | setEvents(events?: Partial<EventObject>[]) {
method bindEventHandlers (line 134) | bindEventHandlers(externalEvents: ReactCalendarExternalEvents) {
method getInstance (line 149) | getInstance() {
method getRootElement (line 153) | getRootElement() {
method render (line 157) | render() {
FILE: apps/react-calendar/src/isEqual.ts
function isEqual (line 18) | function isEqual(a: any, b: any) {
FILE: apps/vue-calendar/example/utils.js
function clone (line 3) | function clone(date) {
function addHours (line 7) | function addHours(d, step) {
function addDate (line 14) | function addDate(d, step) {
function subtractDate (line 21) | function subtractDate(d, steps) {
FILE: apps/vue-calendar/index.d.ts
class VueCalendar (line 4) | class VueCalendar extends Vue {
class VueCalendar (line 10) | class VueCalendar extends Vue {
FILE: apps/vue-calendar/src/Calendar.js
method data (line 38) | data() {
method view (line 44) | view(value) {
method useFormPopup (line 47) | useFormPopup(value) {
method useDetailPopup (line 50) | useDetailPopup(value) {
method isReadOnly (line 53) | isReadOnly(value) {
method eventFilter (line 56) | eventFilter(value) {
method week (line 59) | week(value) {
method month (line 62) | month(value) {
method gridSelection (line 65) | gridSelection(value) {
method timezone (line 68) | timezone(value) {
method theme (line 71) | theme(value) {
method template (line 74) | template(value) {
method calendars (line 77) | calendars(value) {
method events (line 80) | events(value) {
method mounted (line 85) | mounted() {
method beforeDestroy (line 104) | beforeDestroy() {
method addEventListeners (line 109) | addEventListeners() {
method getRootElement (line 114) | getRootElement() {
method getInstance (line 117) | getInstance() {
FILE: libs/date/index.d.ts
type TuiDateConstructor (line 2) | interface TuiDateConstructor {
class DateInterface (line 6) | class DateInterface {
class LocalDate (line 56) | class LocalDate extends DateInterface {}
class UTCDate (line 57) | class UTCDate extends DateInterface {}
class MomentDate (line 58) | class MomentDate extends DateInterface {
FILE: libs/date/src/localDate.js
function throwNotSupported (line 9) | function throwNotSupported() {
function getDateTime (line 13) | function getDateTime(dateString) {
function createFromDateString (line 33) | function createFromDateString(dateString) {
class LocalDate (line 44) | class LocalDate {
method constructor (line 45) | constructor(...args) {
method setTimezoneOffset (line 59) | setTimezoneOffset() {
method setTimezoneName (line 63) | setTimezoneName() {
method clone (line 67) | clone() {
method toDate (line 71) | toDate() {
method toString (line 75) | toString() {
FILE: libs/date/src/momentDate.js
class MomentDate (line 3) | class MomentDate {
method setMoment (line 4) | static setMoment(m) {
method constructor (line 10) | constructor(...args) {
method setTimezoneOffset (line 20) | setTimezoneOffset(offset) {
method setTimezoneName (line 26) | setTimezoneName(zoneName) {
method clone (line 38) | clone() {
method toDate (line 42) | toDate() {
method toString (line 46) | toString() {
method getTime (line 50) | getTime() {
method getTimezoneOffset (line 54) | getTimezoneOffset() {
method getFullYear (line 60) | getFullYear() {
method getMonth (line 64) | getMonth() {
method getDate (line 68) | getDate() {
method getHours (line 72) | getHours() {
method getMinutes (line 76) | getMinutes() {
method getSeconds (line 80) | getSeconds() {
method getMilliseconds (line 84) | getMilliseconds() {
method getDay (line 88) | getDay() {
method setTime (line 92) | setTime(t) {
method setFullYear (line 98) | setFullYear(y, m = this.getMonth(), d = this.getDate()) {
method setMonth (line 104) | setMonth(m, d = this.m.date()) {
method setDate (line 110) | setDate(d) {
method setHours (line 116) | setHours(h, m = this.getMinutes(), s = this.getSeconds(), ms = this.ge...
method setMinutes (line 122) | setMinutes(m, s = this.getSeconds(), ms = this.getMilliseconds()) {
method setSeconds (line 128) | setSeconds(s, ms = this.getMilliseconds()) {
method setMilliseconds (line 134) | setMilliseconds(ms) {
FILE: libs/date/src/utcDate.js
class UTCDate (line 3) | class UTCDate extends LocalDate {
method clone (line 4) | clone() {
method getTimezoneOffset (line 8) | getTimezoneOffset() {
FILE: libs/date/tsBannerGenerator.js
constant TS_BANNER (line 8) | const TS_BANNER = ['// Type definitions for TOAST UI Date v' + pkg.versi...
FILE: libs/date/webpack.config.js
constant BANNER (line 7) | const BANNER = [
Condensed preview — 455 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,687K chars).
[
{
"path": ".eslintignore",
"chars": 33,
"preview": "build/\ndist/\nnode_modules/\nperf/\n"
},
{
"path": ".eslintrc.js",
"chars": 3152,
"preview": "const defaultExtends = [\n 'tui',\n 'prettier',\n 'plugin:@typescript-eslint/recommended',\n 'plugin:react/recommended',"
},
{
"path": ".github/composite-actions/install-dependencies/action.yml",
"chars": 499,
"preview": "name: 'Install root dependencies using cache'\ndescription: 'Set Node.js and install dependencies using cache'\nruns:\n us"
},
{
"path": ".github/workflows/publish-calendar.yml",
"chars": 2381,
"preview": "name: Publish calendar\non: [workflow_dispatch]\nenv:\n WORKING_DIRECTORY: ./apps/calendar\njobs:\n check-version:\n runs"
},
{
"path": ".github/workflows/publish-docs.yml",
"chars": 2237,
"preview": "name: Publish docs\non: [workflow_dispatch]\nenv:\n WORKING_DIRECTORY: ./apps/calendar\njobs:\n publish-docs:\n runs-on: "
},
{
"path": ".github/workflows/publish-wrappers.yml",
"chars": 3045,
"preview": "name: Publish wrapper\non: [workflow_dispatch]\n\nenv:\n WORKING_DIRECTORY: ./apps/calendar\n REACT_WRAPPER_DIRECTORY: ./ap"
},
{
"path": ".github/workflows/test.yml",
"chars": 1277,
"preview": "name: Lint and test\non:\n pull_request:\n branches: [main]\n workflow_call:\njobs:\n lint:\n name: Lint & Type Checki"
},
{
"path": ".gitignore",
"chars": 659,
"preview": "# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nl"
},
{
"path": ".husky/.gitignore",
"chars": 2,
"preview": "_\n"
},
{
"path": ".husky/pre-commit",
"chars": 58,
"preview": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpx lint-staged\n"
},
{
"path": ".prettierignore",
"chars": 12,
"preview": "*.md\n*.html\n"
},
{
"path": ".prettierrc",
"chars": 370,
"preview": "{\n \"singleQuote\": true,\n \"printWidth\": 100,\n \"tabWidth\": 2,\n \"useTabs\": false,\n \"semi\": true,\n \"quoteProps\": \"as-n"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3229,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "CONTRIBUTING.md",
"chars": 5324,
"preview": "# Contributing to TOAST UI\n\nFirst off, thanks for taking the time to contribute! 🎉 😘 ✨\n\nThe following is a set of guidel"
},
{
"path": "LICENSE",
"chars": 1067,
"preview": "\nMIT License\n\nCopyright (c) 2021 NHN Corp.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
},
{
"path": "README.md",
"chars": 6812,
"preview": "#  => 'npm run check-types', 'eslint --fix', 'jest -"
},
{
"path": "apps/calendar/.storybook/main.js",
"chars": 1818,
"preview": "const path = require('path');\n\nmodule.exports = {\n core: {\n builder: 'webpack5',\n },\n stories: ['../**/*.stories.@"
},
{
"path": "apps/calendar/.storybook/manager.js",
"chars": 129,
"preview": "import { addons } from '@storybook/addons';\nimport calendarTheme from './theme';\n\naddons.setConfig({\n theme: calendarTh"
},
{
"path": "apps/calendar/.storybook/preview.js",
"chars": 210,
"preview": "import 'preact/debug';\nimport '@src/css/index.css';\nimport 'tui-date-picker/dist/tui-date-picker.css';\nimport 'tui-time-"
},
{
"path": "apps/calendar/.storybook/theme.js",
"chars": 293,
"preview": "import { create } from '@storybook/theming';\n\nexport default create({\n base: 'light',\n brandTitle: 'TOAST UI Calendar'"
},
{
"path": "apps/calendar/README.md",
"chars": 5552,
"preview": "#  {\n return document.querySelector(selec"
},
{
"path": "apps/calendar/examples/styles/app.css",
"chars": 2080,
"preview": "@import \"https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css\";\n\n.header {\n padding: 1rem;\n border-bottom: 1"
},
{
"path": "apps/calendar/examples/styles/icons.css",
"chars": 1445,
"preview": "/* font icons */\n@font-face {\n font-family: 'tui-calendar-font-icon';\n src: url('../fonts/icon.eot') format('embed"
},
{
"path": "apps/calendar/examples/styles/reset.css",
"chars": 488,
"preview": "@import url(https://fonts.googleapis.com/css?family=Noto+Sans);\n\n*, *::before, *::after {\n box-sizing: border-box;\n}\n"
},
{
"path": "apps/calendar/jest.config.js",
"chars": 660,
"preview": "module.exports = {\n testEnvironment: 'jsdom',\n clearMocks: true,\n preset: 'ts-jest',\n moduleFileExtensions: ['js', '"
},
{
"path": "apps/calendar/jsdoc.conf.json",
"chars": 804,
"preview": "{\n \"source\": {\n \"include\": [\n \"src/js/factory/calendar.js\",\n \"src/js/theme/themeConfig.js\",\n \"src/js/"
},
{
"path": "apps/calendar/package.json",
"chars": 3525,
"preview": "{\n \"name\": \"@toast-ui/calendar\",\n \"author\": \"NHN Cloud FE Development Lab <dl_javascript@nhn.com>\",\n \"version\": \"2.1."
},
{
"path": "apps/calendar/playwright/assertions.ts",
"chars": 5369,
"preview": "import type { Locator, Page } from '@playwright/test';\nimport { expect } from '@playwright/test';\n\nimport type { Formatt"
},
{
"path": "apps/calendar/playwright/configs.ts",
"chars": 825,
"preview": "const PORT = process.env.CI ? 8080 : 6006;\n\nconst generatePageUrl = (viewId: string) =>\n `http://localhost:${PORT}/ifra"
},
{
"path": "apps/calendar/playwright/constants.ts",
"chars": 73,
"preview": "export enum ClickDelay {\n Immediate = 1,\n Short = 100,\n Long = 300,\n}\n"
},
{
"path": "apps/calendar/playwright/day/timeGridEventMoving.e2e.ts",
"chars": 7516,
"preview": "import { expect, test } from '@playwright/test';\nimport type { Matchers } from '@playwright/test/types/expect-types';\n\ni"
},
{
"path": "apps/calendar/playwright/day/timeGridEventResizing.e2e.ts",
"chars": 6778,
"preview": "import type { Page } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\nimport type { Matchers } "
},
{
"path": "apps/calendar/playwright/day/timeGridScrollSync.e2e.ts",
"chars": 7200,
"preview": "import type { Page } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\n\nimport { mockDayViewEven"
},
{
"path": "apps/calendar/playwright/day/timeGridSelection.e2e.ts",
"chars": 4750,
"preview": "import { expect, test } from '@playwright/test';\n\nimport { assertTimeGridSelection } from '../assertions';\nimport { DAY_"
},
{
"path": "apps/calendar/playwright/month/accumulatedGridSelection.e2e.ts",
"chars": 1017,
"preview": "import { test } from '@playwright/test';\n\nimport { assertAccumulatedDayGridSelectionMatching } from '../assertions';\nimp"
},
{
"path": "apps/calendar/playwright/month/eventMoving.e2e.ts",
"chars": 10025,
"preview": "import type { Page } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\n\nimport type { EventObjec"
},
{
"path": "apps/calendar/playwright/month/eventResizing.e2e.ts",
"chars": 9774,
"preview": "import type { Locator } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\n\nimport { mockMonthVie"
},
{
"path": "apps/calendar/playwright/month/gridSelection.e2e.ts",
"chars": 3681,
"preview": "import type { Page } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\n\nimport { assertDayGridSe"
},
{
"path": "apps/calendar/playwright/month/seeMoreEventsPopup.e2e.ts",
"chars": 701,
"preview": "import { expect, test } from '@playwright/test';\n\nimport { MONTH_VIEW_PAGE_URL } from '../configs';\n\ntest.beforeEach(asy"
},
{
"path": "apps/calendar/playwright/month/visibleEventCount.e2e.ts",
"chars": 1680,
"preview": "import { expect, test } from '@playwright/test';\n\nimport { MONTH_VIEW_PAGE_URL } from '../configs';\nimport { getCellSele"
},
{
"path": "apps/calendar/playwright/playwright-env.d.ts",
"chars": 118,
"preview": "import type Calendar from '../src/factory/calendar';\n\ndeclare global {\n interface Window {\n $cal: Calendar;\n }\n}\n"
},
{
"path": "apps/calendar/playwright/types.ts",
"chars": 236,
"preview": "export type BoundingBox = {\n x: number;\n y: number;\n width: number;\n height: number;\n};\n\nexport enum Direction {\n U"
},
{
"path": "apps/calendar/playwright/utils.ts",
"chars": 3337,
"preview": "import type { Locator, Page } from '@playwright/test';\nimport { expect } from '@playwright/test';\n\nimport type TZDate fr"
},
{
"path": "apps/calendar/playwright/week/alldayGridEventMoving.e2e.ts",
"chars": 5698,
"preview": "import type { Locator } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\n\nimport { mockWeekView"
},
{
"path": "apps/calendar/playwright/week/alldayGridEventResizing.e2e.ts",
"chars": 4266,
"preview": "import type { Locator } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\n\nimport { mockWeekView"
},
{
"path": "apps/calendar/playwright/week/dayGridSelection.e2e.ts",
"chars": 2713,
"preview": "import type { Page } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\n\nimport { assertDayGridSe"
},
{
"path": "apps/calendar/playwright/week/hourStartOption.e2e.ts",
"chars": 1525,
"preview": "import { expect, test } from '@playwright/test';\n\nimport { WEEK_VIEW_PAGE_URL } from '../configs';\nimport { dragAndDrop,"
},
{
"path": "apps/calendar/playwright/week/primaryTimezone.e2e.ts",
"chars": 1298,
"preview": "import { expect, test } from '@playwright/test';\n\nimport { mockWeekViewEvents } from '../../stories/mocks/mockWeekViewEv"
},
{
"path": "apps/calendar/playwright/week/timeGridEventClick.e2e.ts",
"chars": 5860,
"preview": "import { expect, test } from '@playwright/test';\nimport type { BoundingBox } from 'playwright/types';\n\nimport { mockWeek"
},
{
"path": "apps/calendar/playwright/week/timeGridEventMoving.e2e.ts",
"chars": 11199,
"preview": "import type { Locator } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\n\nimport type TZDate fr"
},
{
"path": "apps/calendar/playwright/week/timeGridEventResizing.e2e.ts",
"chars": 14337,
"preview": "import type { Page } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\nimport type { Matchers } "
},
{
"path": "apps/calendar/playwright/week/timeGridScrollSync.e2e.ts",
"chars": 6446,
"preview": "import type { Page } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\n\nimport { WEEK_VIEW_PAGE_"
},
{
"path": "apps/calendar/playwright/week/timeGridSelection.e2e.ts",
"chars": 13915,
"preview": "import { expect, test } from '@playwright/test';\n\nimport { assertTimeGridSelection } from '../assertions';\nimport { WEEK"
},
{
"path": "apps/calendar/postcss.config.js",
"chars": 184,
"preview": "module.exports = {\n plugins: [\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n require('postcss-"
},
{
"path": "apps/calendar/scripts/publishToCDN.js",
"chars": 2518,
"preview": "/* eslint-disable */\nconst path = require('path');\nconst fs = require('fs');\nconst fetch = require('node-fetch');\nconst "
},
{
"path": "apps/calendar/scripts/updateWrapper.js",
"chars": 894,
"preview": "/* eslint-disable */\nconst path = require('path');\nconst fs = require('fs');\n\nconst CORE_PACKAGE_JSON_PATH = path.join(_"
},
{
"path": "apps/calendar/src/calendarContainer.tsx",
"chars": 1074,
"preview": "import { h } from 'preact';\n\nimport { StoreProvider } from '@src/contexts/calendarStore';\nimport { EventBusProvider } fr"
},
{
"path": "apps/calendar/src/components/dayGridCommon/dayName.tsx",
"chars": 2941,
"preview": "import { h } from 'preact';\n\nimport type { DayNameThemes } from '@src/components/dayGridCommon/gridHeader';\nimport { Tem"
},
{
"path": "apps/calendar/src/components/dayGridCommon/gridHeader.tsx",
"chars": 3034,
"preview": "import { h } from 'preact';\n\nimport { DayName } from '@src/components/dayGridCommon/dayName';\nimport { DEFAULT_DAY_NAME_"
},
{
"path": "apps/calendar/src/components/dayGridCommon/gridSelection.tsx",
"chars": 1244,
"preview": "import { h } from 'preact';\n\nimport { useTheme } from '@src/contexts/themeStore';\nimport { cls, toPercent } from '@src/h"
},
{
"path": "apps/calendar/src/components/dayGridMonth/accumulatedGridSelection.tsx",
"chars": 1240,
"preview": "import { h } from 'preact';\nimport { useCallback } from 'preact/hooks';\n\nimport { GridSelection } from '@src/components/"
},
{
"path": "apps/calendar/src/components/dayGridMonth/cellHeader.tsx",
"chars": 3333,
"preview": "import { h } from 'preact';\nimport { useMemo } from 'preact/hooks';\n\nimport { MoreEventsButton } from '@src/components/d"
},
{
"path": "apps/calendar/src/components/dayGridMonth/dayGridMonth.tsx",
"chars": 6182,
"preview": "import { h } from 'preact';\nimport { useEffect, useMemo, useRef, useState } from 'preact/hooks';\n\nimport { AccumulatedGr"
},
{
"path": "apps/calendar/src/components/dayGridMonth/gridCell.tsx",
"chars": 6507,
"preview": "import { h } from 'preact';\nimport { useCallback, useEffect, useState } from 'preact/hooks';\n\nimport { CellHeader } from"
},
{
"path": "apps/calendar/src/components/dayGridMonth/gridRow.tsx",
"chars": 1701,
"preview": "import { h } from 'preact';\nimport { memo } from 'preact/compat';\nimport { useCallback } from 'preact/hooks';\n\nimport { "
},
{
"path": "apps/calendar/src/components/dayGridMonth/gridSelectionByRow.tsx",
"chars": 1120,
"preview": "import { h } from 'preact';\nimport { useCallback } from 'preact/hooks';\n\nimport { GridSelection } from '@src/components/"
},
{
"path": "apps/calendar/src/components/dayGridMonth/monthEvents.tsx",
"chars": 1220,
"preview": "import { h } from 'preact';\nimport { memo } from 'preact/compat';\n\nimport { HorizontalEvent } from '@src/components/even"
},
{
"path": "apps/calendar/src/components/dayGridMonth/moreEventsButton.tsx",
"chars": 1031,
"preview": "import { h } from 'preact';\n\nimport { Template } from '@src/components/template';\nimport { CellBarType } from '@src/cons"
},
{
"path": "apps/calendar/src/components/dayGridMonth/movingEventShadow.tsx",
"chars": 1184,
"preview": "import type { ComponentProps } from 'preact';\nimport { h } from 'preact';\n\nimport type { DayGridMonth } from '@src/compo"
},
{
"path": "apps/calendar/src/components/dayGridMonth/resizingGuideByRow.tsx",
"chars": 1595,
"preview": "import type { ComponentProps } from 'preact';\nimport { h } from 'preact';\n\nimport type { DayGridMonth } from '@src/compo"
},
{
"path": "apps/calendar/src/components/dayGridWeek/alldayGridRow.tsx",
"chars": 4822,
"preview": "import { Fragment, h } from 'preact';\nimport { useMemo } from 'preact/hooks';\n\nimport { AlldayGridSelection } from '@src"
},
{
"path": "apps/calendar/src/components/dayGridWeek/alldayGridSelection.tsx",
"chars": 1102,
"preview": "import type { ComponentProps } from 'preact';\nimport { h } from 'preact';\n\nimport { GridSelection } from '@src/component"
},
{
"path": "apps/calendar/src/components/dayGridWeek/gridCell.tsx",
"chars": 2140,
"preview": "import { h } from 'preact';\nimport { useCallback } from 'preact/hooks';\n\nimport { Template } from '@src/components/templ"
},
{
"path": "apps/calendar/src/components/dayGridWeek/gridCells.tsx",
"chars": 2034,
"preview": "import { Fragment, h } from 'preact';\nimport { memo } from 'preact/compat';\n\nimport { GridCell } from '@src/components/d"
},
{
"path": "apps/calendar/src/components/dayGridWeek/movingEventShadow.tsx",
"chars": 1070,
"preview": "import type { ComponentProps } from 'preact';\nimport { h } from 'preact';\n\nimport type { AlldayGridRow } from '@src/comp"
},
{
"path": "apps/calendar/src/components/dayGridWeek/otherGridRow.tsx",
"chars": 2888,
"preview": "import { Fragment, h } from 'preact';\nimport { useMemo } from 'preact/hooks';\n\nimport { GridCells } from '@src/component"
},
{
"path": "apps/calendar/src/components/dayGridWeek/resizingEventShadow.tsx",
"chars": 1067,
"preview": "import type { ComponentProps } from 'preact';\nimport { h } from 'preact';\n\nimport type { AlldayGridRow } from '@src/comp"
},
{
"path": "apps/calendar/src/components/events/backgroundEvent.tsx",
"chars": 703,
"preview": "import { h } from 'preact';\n\nimport { cls } from '@src/helpers/css';\nimport type EventUIModel from '@src/model/eventUIMo"
},
{
"path": "apps/calendar/src/components/events/horizontalEvent.spec.tsx",
"chars": 9569,
"preview": "import { h } from 'preact';\n\nimport { HorizontalEvent } from '@src/components/events/horizontalEvent';\nimport { initCale"
},
{
"path": "apps/calendar/src/components/events/horizontalEvent.tsx",
"chars": 8625,
"preview": "import { h } from 'preact';\nimport { useEffect, useRef, useState } from 'preact/hooks';\n\nimport { HorizontalEventResizeI"
},
{
"path": "apps/calendar/src/components/events/horizontalEventResizeIcon.tsx",
"chars": 508,
"preview": "import { h } from 'preact';\n\nimport { cls } from '@src/helpers/css';\n\nimport type { MouseEventListener } from '@t/util';"
},
{
"path": "apps/calendar/src/components/events/timeEvent.spec.tsx",
"chars": 7449,
"preview": "import { h } from 'preact';\n\nimport { TimeEvent } from '@src/components/events/timeEvent';\nimport { initCalendarStore } "
},
{
"path": "apps/calendar/src/components/events/timeEvent.tsx",
"chars": 9422,
"preview": "import { h } from 'preact';\nimport { useEffect, useRef, useState } from 'preact/hooks';\n\nimport { Template } from '@src/"
},
{
"path": "apps/calendar/src/components/layout.tsx",
"chars": 3103,
"preview": "import type { ComponentChildren, ComponentProps } from 'preact';\nimport { h, toChildArray } from 'preact';\nimport { useL"
},
{
"path": "apps/calendar/src/components/panel.tsx",
"chars": 3453,
"preview": "import { Fragment, h } from 'preact';\nimport { forwardRef } from 'preact/compat';\nimport { useCallback, useLayoutEffect,"
},
{
"path": "apps/calendar/src/components/panelResizer.tsx",
"chars": 2120,
"preview": "import { h } from 'preact';\nimport { useCallback, useRef, useState } from 'preact/hooks';\n\nimport { useDispatch } from '"
},
{
"path": "apps/calendar/src/components/popup/calendarDropdownMenu.tsx",
"chars": 1536,
"preview": "import { h } from 'preact';\n\nimport { cls } from '@src/helpers/css';\n\nimport type { CalendarInfo } from '@t/options';\n\ni"
},
{
"path": "apps/calendar/src/components/popup/calendarSelector.tsx",
"chars": 1896,
"preview": "import { h } from 'preact';\n\nimport { CalendarDropdownMenu } from '@src/components/popup/calendarDropdownMenu';\nimport {"
},
{
"path": "apps/calendar/src/components/popup/closePopupButton.tsx",
"chars": 902,
"preview": "import { h } from 'preact';\n\nimport { Template } from '@src/components/template';\nimport { useDispatch } from '@src/cont"
},
{
"path": "apps/calendar/src/components/popup/confirmPopupButton.tsx",
"chars": 410,
"preview": "import { h } from 'preact';\n\nimport { cls } from '@src/helpers/css';\n\nimport type { PropsWithChildren } from '@t/compone"
},
{
"path": "apps/calendar/src/components/popup/dateSelector.tsx",
"chars": 4651,
"preview": "import type { RefObject } from 'preact';\nimport { h } from 'preact';\nimport { forwardRef } from 'preact/compat';\nimport "
},
{
"path": "apps/calendar/src/components/popup/eventDetailPopup.spec.tsx",
"chars": 4986,
"preview": "import { h } from 'preact';\n\nimport { EventDetailPopup } from '@src/components/popup/eventDetailPopup';\nimport { initCal"
},
{
"path": "apps/calendar/src/components/popup/eventDetailPopup.tsx",
"chars": 6740,
"preview": "import { h } from 'preact';\nimport { createPortal } from 'preact/compat';\nimport { useLayoutEffect, useMemo, useRef, use"
},
{
"path": "apps/calendar/src/components/popup/eventDetailSectionDetail.tsx",
"chars": 2851,
"preview": "import { h } from 'preact';\n\nimport { Template } from '@src/components/template';\nimport { cls } from '@src/helpers/css'"
},
{
"path": "apps/calendar/src/components/popup/eventDetailSectionHeader.tsx",
"chars": 758,
"preview": "import { h } from 'preact';\n\nimport { Template } from '@src/components/template';\nimport { cls } from '@src/helpers/css'"
},
{
"path": "apps/calendar/src/components/popup/eventFormPopup.spec.tsx",
"chars": 8161,
"preview": "import { h } from 'preact';\nimport { useCallback, useEffect } from 'preact/hooks';\n\nimport { EventFormPopup } from '@src"
},
{
"path": "apps/calendar/src/components/popup/eventFormPopup.tsx",
"chars": 8699,
"preview": "import { h } from 'preact';\nimport { createPortal } from 'preact/compat';\nimport { useEffect, useLayoutEffect, useMemo, "
},
{
"path": "apps/calendar/src/components/popup/eventStateSelector.tsx",
"chars": 1828,
"preview": "import { h } from 'preact';\n\nimport { PopupSection } from '@src/components/popup/popupSection';\nimport { StateDropdownMe"
},
{
"path": "apps/calendar/src/components/popup/locationInputBox.tsx",
"chars": 1440,
"preview": "import { h } from 'preact';\nimport type { ChangeEventHandler } from 'preact/compat';\n\nimport { PopupSection } from '@src"
},
{
"path": "apps/calendar/src/components/popup/popupOverlay.tsx",
"chars": 847,
"preview": "import { h } from 'preact';\n\nimport { useDispatch, useStore } from '@src/contexts/calendarStore';\nimport { cls } from '@"
},
{
"path": "apps/calendar/src/components/popup/popupSection.tsx",
"chars": 477,
"preview": "import { h } from 'preact';\n\nimport { cls } from '@src/helpers/css';\nimport { noop } from '@src/utils/noop';\n\nimport typ"
},
{
"path": "apps/calendar/src/components/popup/seeMoreEventsPopup.tsx",
"chars": 3307,
"preview": "import { h } from 'preact';\nimport { createPortal } from 'preact/compat';\nimport { useEffect, useRef } from 'preact/hook"
},
{
"path": "apps/calendar/src/components/popup/stateDropdownMenu.tsx",
"chars": 1301,
"preview": "import { h } from 'preact';\n\nimport { Template } from '@src/components/template';\nimport { cls } from '@src/helpers/css'"
},
{
"path": "apps/calendar/src/components/popup/titleInputBox.tsx",
"chars": 2055,
"preview": "import { h } from 'preact';\nimport type { ChangeEventHandler } from 'preact/compat';\n\nimport { PopupSection } from '@src"
},
{
"path": "apps/calendar/src/components/template.tsx",
"chars": 1152,
"preview": "import { cloneElement, createElement } from 'preact';\n\nimport { useStore } from '@src/contexts/calendarStore';\nimport { "
},
{
"path": "apps/calendar/src/components/timeGrid/column.tsx",
"chars": 5106,
"preview": "import { h } from 'preact';\nimport { memo } from 'preact/compat';\nimport { useCallback } from 'preact/hooks';\n\nimport { "
},
{
"path": "apps/calendar/src/components/timeGrid/gridLines.tsx",
"chars": 1262,
"preview": "import { h } from 'preact';\nimport { memo } from 'preact/compat';\n\nimport { useTheme } from '@src/contexts/themeStore';\n"
},
{
"path": "apps/calendar/src/components/timeGrid/gridSelectionByColumn.tsx",
"chars": 2532,
"preview": "import { h } from 'preact';\nimport { useCallback, useMemo } from 'preact/hooks';\n\nimport { useStore } from '@src/context"
},
{
"path": "apps/calendar/src/components/timeGrid/index.ts",
"chars": 338,
"preview": "import type { TimeUnit } from '@t/events';\n\nexport const className = 'timegrid';\nexport const addTimeGridPrefix = (selec"
},
{
"path": "apps/calendar/src/components/timeGrid/movingEventShadow.tsx",
"chars": 677,
"preview": "import { h } from 'preact';\n\nimport { TimeEvent } from '@src/components/events/timeEvent';\nimport { useTimeGridEventMove"
},
{
"path": "apps/calendar/src/components/timeGrid/nowIndicator.tsx",
"chars": 3524,
"preview": "import { h } from 'preact';\nimport { useEffect, useRef } from 'preact/hooks';\n\nimport { addTimeGridPrefix } from '@src/c"
},
{
"path": "apps/calendar/src/components/timeGrid/nowIndicatorLabel.tsx",
"chars": 1520,
"preview": "import { h } from 'preact';\nimport { useCallback, useMemo } from 'preact/hooks';\n\nimport { Template } from '@src/compone"
},
{
"path": "apps/calendar/src/components/timeGrid/resizingGuideByColumn.tsx",
"chars": 847,
"preview": "import { h } from 'preact';\n\nimport { TimeEvent } from '@src/components/events/timeEvent';\nimport { useTimeGridEventResi"
},
{
"path": "apps/calendar/src/components/timeGrid/timeColumn.tsx",
"chars": 7167,
"preview": "import { h } from 'preact';\nimport { memo } from 'preact/compat';\nimport { useCallback, useMemo } from 'preact/hooks';\n\n"
},
{
"path": "apps/calendar/src/components/timeGrid/timeGrid.spec.tsx",
"chars": 4331,
"preview": "import { h } from 'preact';\n\nimport { TimeGrid } from '@src/components/timeGrid/timeGrid';\nimport { toPercent } from '@s"
},
{
"path": "apps/calendar/src/components/timeGrid/timeGrid.tsx",
"chars": 7206,
"preview": "import { h } from 'preact';\nimport { useCallback, useLayoutEffect, useMemo, useState } from 'preact/hooks';\n\nimport { ad"
},
{
"path": "apps/calendar/src/components/timeGrid/timezoneCollapseButton.tsx",
"chars": 704,
"preview": "import { h } from 'preact';\n\nimport { addTimeGridPrefix } from '@src/components/timeGrid';\nimport { useEventBus } from '"
},
{
"path": "apps/calendar/src/components/timeGrid/timezoneCollpaseButton.spec.tsx",
"chars": 1049,
"preview": "import { h } from 'preact';\n\nimport { TimezoneCollapseButton } from '@src/components/timeGrid/timezoneCollapseButton';\ni"
},
{
"path": "apps/calendar/src/components/timeGrid/timezoneLabels.tsx",
"chars": 3504,
"preview": "import { h } from 'preact';\nimport { useMemo } from 'preact/hooks';\n\nimport { Template } from '@src/components/template'"
},
{
"path": "apps/calendar/src/components/view/day.spec.tsx",
"chars": 3666,
"preview": "import { h } from 'preact';\n\nimport { Day } from '@src/components/view/day';\nimport { DEFAULT_EVENT_PANEL, DEFAULT_TASK_"
},
{
"path": "apps/calendar/src/components/view/day.tsx",
"chars": 5492,
"preview": "import { h } from 'preact';\nimport { useCallback, useMemo } from 'preact/hooks';\n\nimport { GridHeader } from '@src/compo"
},
{
"path": "apps/calendar/src/components/view/main.tsx",
"chars": 732,
"preview": "import type { FunctionComponent } from 'preact';\nimport { h } from 'preact';\nimport { useMemo } from 'preact/hooks';\n\nim"
},
{
"path": "apps/calendar/src/components/view/month.spec.tsx",
"chars": 5596,
"preview": "import { h } from 'preact';\n\nimport { Month } from '@src/components/view/month';\nimport { initCalendarStore } from '@src"
},
{
"path": "apps/calendar/src/components/view/month.tsx",
"chars": 2252,
"preview": "import { h } from 'preact';\nimport { useMemo } from 'preact/hooks';\n\nimport { GridHeader } from '@src/components/dayGrid"
},
{
"path": "apps/calendar/src/components/view/week.spec.tsx",
"chars": 5272,
"preview": "import { h } from 'preact';\n\nimport { Week } from '@src/components/view/week';\nimport { DEFAULT_EVENT_PANEL, DEFAULT_TAS"
},
{
"path": "apps/calendar/src/components/view/week.tsx",
"chars": 5806,
"preview": "import { h } from 'preact';\nimport { useCallback, useMemo } from 'preact/hooks';\n\nimport { GridHeader } from '@src/compo"
},
{
"path": "apps/calendar/src/constants/error.ts",
"chars": 187,
"preview": "export const INVALID_DATETIME_FORMAT = 'Invalid DateTime Format';\nexport const INVALID_TIMEZONE_NAME = 'Invalid IANA Tim"
},
{
"path": "apps/calendar/src/constants/grid.ts",
"chars": 111,
"preview": "export const DEFAULT_VISIBLE_WEEKS = 6;\n\nexport enum CellBarType {\n header = 'header',\n footer = 'footer',\n}\n"
},
{
"path": "apps/calendar/src/constants/keyboard.ts",
"chars": 111,
"preview": "export enum KEY {\n ESCAPE = 'Escape',\n}\n\nexport const KEYCODE: Record<KEY, number> = {\n [KEY.ESCAPE]: 27,\n};\n"
},
{
"path": "apps/calendar/src/constants/layout.ts",
"chars": 89,
"preview": "export const DEFAULT_RESIZER_LENGTH = 3;\n\nexport const DEFAULT_DUPLICATE_EVENT_CID = -1;\n"
},
{
"path": "apps/calendar/src/constants/message.ts",
"chars": 54,
"preview": "export const MESSAGE_PREFIX = '@toast-ui/calendar: ';\n"
},
{
"path": "apps/calendar/src/constants/mouse.ts",
"chars": 46,
"preview": "export const MINIMUM_DRAG_MOUSE_DISTANCE = 3;\n"
},
{
"path": "apps/calendar/src/constants/popup.ts",
"chars": 707,
"preview": "import { cls } from '@src/helpers/css';\n\nimport type { BooleanKeyOfEventObject } from '@t/events';\n\nexport const SEE_MOR"
},
{
"path": "apps/calendar/src/constants/statistics.ts",
"chars": 48,
"preview": "export const GA_TRACKING_ID = 'UA-129951699-1';\n"
},
{
"path": "apps/calendar/src/constants/style.ts",
"chars": 1487,
"preview": "// common day name\nexport const DEFAULT_DAY_NAME_MARGIN_LEFT = '0';\n\n// month day name\nexport const MONTH_DAY_NAME_HEIGH"
},
{
"path": "apps/calendar/src/constants/theme.ts",
"chars": 2527,
"preview": "import type { DeepRequired } from 'ts-essentials';\n\nimport type { CommonTheme, MonthTheme, WeekTheme } from '@t/theme';\n"
},
{
"path": "apps/calendar/src/constants/view.ts",
"chars": 315,
"preview": "import type { EventView, TaskView, ViewType } from '@t/options';\n\nexport const VIEW_TYPE: {\n [key: string]: ViewType;\n}"
},
{
"path": "apps/calendar/src/contexts/calendarStore.ts",
"chars": 2419,
"preview": "import { useCallback } from 'preact/hooks';\n\nimport { createCalendarDispatchers, createCalendarSlice } from '@src/slices"
},
{
"path": "apps/calendar/src/contexts/eventBus.spec.tsx",
"chars": 3680,
"preview": "import { h } from 'preact';\nimport { useLayoutEffect } from 'preact/hooks';\n\nimport { EventBusProvider, useEventBus } fr"
},
{
"path": "apps/calendar/src/contexts/eventBus.tsx",
"chars": 586,
"preview": "import { createContext } from 'preact';\nimport { useContext } from 'preact/hooks';\n\nimport type { EventBus } from '@src/"
},
{
"path": "apps/calendar/src/contexts/floatingLayer.tsx",
"chars": 2149,
"preview": "import { createContext, h } from 'preact';\nimport { useContext } from 'preact/hooks';\n\nimport {\n EVENT_DETAIL_POPUP_SLO"
},
{
"path": "apps/calendar/src/contexts/layoutContainer.tsx",
"chars": 483,
"preview": "import { createContext } from 'preact';\nimport { useContext } from 'preact/hooks';\n\nimport { isUndefined } from '@src/ut"
},
{
"path": "apps/calendar/src/contexts/themeStore.tsx",
"chars": 1925,
"preview": "import { useCallback } from 'preact/hooks';\n\nimport { commonThemeSelector, monthThemeSelector, weekThemeSelector } from "
},
{
"path": "apps/calendar/src/controller/base.spec.ts",
"chars": 5582,
"preview": "import {\n createEvent,\n createEventCollection,\n deleteEvent,\n findByDateRange,\n getDateRange,\n updateEvent,\n} from"
},
{
"path": "apps/calendar/src/controller/base.ts",
"chars": 5436,
"preview": "import { isSameEvent } from '@src/helpers/events';\nimport EventModel from '@src/model/eventModel';\nimport type EventUIMo"
},
{
"path": "apps/calendar/src/controller/column.spec.ts",
"chars": 4714,
"preview": "import { DEFAULT_DUPLICATE_EVENT_CID } from '@src/constants/layout';\nimport {\n COLLAPSED_DUPLICATE_EVENT_WIDTH_PX,\n TI"
},
{
"path": "apps/calendar/src/controller/column.ts",
"chars": 10004,
"preview": "import { DEFAULT_DUPLICATE_EVENT_CID } from '@src/constants/layout';\nimport {\n COLLAPSED_DUPLICATE_EVENT_WIDTH_PX,\n TI"
},
{
"path": "apps/calendar/src/controller/core.spec.ts",
"chars": 12862,
"preview": "import {\n getCollisionGroup,\n getEventInDateRangeFilter,\n getLastRowInColumn,\n getMatrices,\n limitRenderRange,\n} fr"
},
{
"path": "apps/calendar/src/controller/core.ts",
"chars": 7082,
"preview": "import type EventModel from '@src/model/eventModel';\nimport EventUIModel from '@src/model/eventUIModel';\nimport TZDate f"
},
{
"path": "apps/calendar/src/controller/month.spec.ts",
"chars": 6578,
"preview": "import { addEvent, createEventCollection } from '@src/controller/base';\nimport { findByDateRange } from '@src/controller"
},
{
"path": "apps/calendar/src/controller/month.ts",
"chars": 6379,
"preview": "import {\n convertToUIModel,\n getCollisionGroup,\n getEventInDateRangeFilter,\n getMatrices,\n limitRenderRange,\n posi"
},
{
"path": "apps/calendar/src/controller/times.spec.ts",
"chars": 6843,
"preview": "import { getNextGridTime, getPrevGridTime, getTopPercentByTime } from '@src/controller/times';\nimport TZDate from '@src/"
},
{
"path": "apps/calendar/src/controller/times.ts",
"chars": 2940,
"preview": "import type TZDate from '@src/time/date';\nimport { clone } from '@src/time/datetime';\nimport { limit, ratio } from '@src"
},
{
"path": "apps/calendar/src/controller/week.spec.ts",
"chars": 8203,
"preview": "import { addToMatrix, createEvent, createEventCollection } from '@src/controller/base';\nimport { _makeHourRangeFilter, f"
},
{
"path": "apps/calendar/src/controller/week.ts",
"chars": 8441,
"preview": "import { filterByCategory, getDateRange } from '@src/controller/base';\nimport {\n convertToUIModel,\n getCollisionGroup,"
},
{
"path": "apps/calendar/src/css/common.css",
"chars": 46,
"preview": ".holiday {\n color: red;\n font-size: 15px;\n}\n"
},
{
"path": "apps/calendar/src/css/daygrid/dayGrid.css",
"chars": 1269,
"preview": ".layout.month {\n height: 100%;\n}\n\n.month .day-names {\n /* from constant MONTH_DAY_NAME_HEIGHT */\n height: 31px;\n}\n\n.m"
},
{
"path": "apps/calendar/src/css/daygrid/dayNames.css",
"chars": 690,
"preview": ".day-names {\n position: relative;\n}\n\n.day-name-container {\n position: relative;\n}\n\n.day-name-item {\n position: absolu"
},
{
"path": "apps/calendar/src/css/daygrid/index.css",
"chars": 51,
"preview": "@import './dayNames.css';\n@import './dayGrid.css';\n"
},
{
"path": "apps/calendar/src/css/events/background.css",
"chars": 42,
"preview": ".event-background { position: absolute; }\n"
},
{
"path": "apps/calendar/src/css/events/grid.css",
"chars": 777,
"preview": ".weekday-event-title {\n display: block;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding"
},
{
"path": "apps/calendar/src/css/events/index.css",
"chars": 72,
"preview": "@import './background.css';\n@import './time.css';\n@import './grid.css';\n"
},
{
"path": "apps/calendar/src/css/events/time.css",
"chars": 429,
"preview": ".event-time {\n position: absolute;\n overflow: hidden;\n cursor: pointer;\n}\n\n.event-time .travel-time,\n.event-time .eve"
},
{
"path": "apps/calendar/src/css/icons.css",
"chars": 1914,
"preview": ".icon {\n width: 14px;\n height: 14px;\n display: inline-block;\n vertical-align: middle;\n}\n.icon.ic-title {\n backgroun"
},
{
"path": "apps/calendar/src/css/index.css",
"chars": 222,
"preview": "@import './common.css';\n@import './layout.css';\n@import './icons.css';\n@import './timegrid/index.css';\n@import './events"
},
{
"path": "apps/calendar/src/css/layout.css",
"chars": 594,
"preview": ".layout {\n box-sizing: border-box;\n position: relative;\n white-space: nowrap;\n}\n\n.layout * {\n box-sizing: border-box"
},
{
"path": "apps/calendar/src/css/panel/allday.css",
"chars": 1788,
"preview": ".panel-title {\n display: table;\n float: left;\n height: 100%;\n padding-right: 5px;\n}\n\n.panel-title .left-content {\n "
},
{
"path": "apps/calendar/src/css/panel/index.css",
"chars": 24,
"preview": "@import './allday.css';\n"
},
{
"path": "apps/calendar/src/css/popup/common.css",
"chars": 1180,
"preview": ".floating-layer {\n z-index: 1;\n}\n\n.floating-layer * {\n box-sizing: border-box;\n}\n\n.popup-overlay {\n width: 100%;\n he"
},
{
"path": "apps/calendar/src/css/popup/detail.css",
"chars": 2286,
"preview": ".detail-container {\n width: 301px;\n min-width: 301px;\n box-shadow: 0 2px 6px 0 rgb(0 0 0 / 10%);\n background-color: "
},
{
"path": "apps/calendar/src/css/popup/form.css",
"chars": 3590,
"preview": ".form-container {\n min-width: 474px;\n box-shadow: 0 2px 6px 0 rgb(0 0 0 / 10%);\n background-color: #fff;\n border: 1p"
},
{
"path": "apps/calendar/src/css/popup/index.css",
"chars": 95,
"preview": "@import './common.css';\n@import './seeMore.css';\n@import './form.css';\n@import './detail.css';\n"
},
{
"path": "apps/calendar/src/css/popup/seeMore.css",
"chars": 365,
"preview": ".see-more-container {\n display: block;\n position: absolute;\n z-index: 1;\n}\n\n.see-more {\n height: inherit;\n padding:"
},
{
"path": "apps/calendar/src/css/timegrid/column.css",
"chars": 374,
"preview": ".column {\n position: relative;\n}\n\n.column .gridline-half {\n position: absolute;\n width: 100%;\n}\n\n.column .grid-select"
},
{
"path": "apps/calendar/src/css/timegrid/index.css",
"chars": 78,
"preview": "@import './timeColumn.css';\n@import './column.css';\n@import './timegrid.css';\n"
},
{
"path": "apps/calendar/src/css/timegrid/timeColumn.css",
"chars": 1861,
"preview": ".timegrid-time-column {\n font-size: 11px;\n height: 100%;\n}\n\n.timegrid-time-column .timegrid-hour-rows {\n display: inl"
},
{
"path": "apps/calendar/src/css/timegrid/timegrid.css",
"chars": 992,
"preview": ".panel.time {\n overflow-y: auto;\n}\n\n.timegrid {\n user-select: none;\n position: relative;\n height: 200%;\n min-height"
},
{
"path": "apps/calendar/src/factory/__snapshots__/calendarCore.spec.tsx.snap",
"chars": 5695,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`getOptions/setOptions should get options 1`] = `\nObject {\n \"defaul"
},
{
"path": "apps/calendar/src/factory/calendar.tsx",
"chars": 1047,
"preview": "import { h } from 'preact';\n\nimport { Main } from '@src/components/view/main';\nimport { VIEW_TYPE } from '@src/constants"
}
]
// ... and 255 more files (download for full content)
About this extraction
This page contains the full source code of the nhn/tui.calendar GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 455 files (1.5 MB), approximately 423.2k tokens, and a symbol index with 1199 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.