@fullcalendar_timegrid.js 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267
  1. import {
  2. DayTable
  3. } from "./chunk-INZMDDGR.js";
  4. import "./chunk-DAAU2ANU.js";
  5. import {
  6. BaseComponent,
  7. BgEvent,
  8. ContentContainer,
  9. DateComponent,
  10. DayCellContainer,
  11. DayHeader,
  12. DaySeriesModel,
  13. DayTableModel,
  14. MoreLinkContainer,
  15. NowIndicatorContainer,
  16. NowTimer,
  17. PositionCache,
  18. RefMap,
  19. SegHierarchy,
  20. SimpleScrollGrid,
  21. Slicer,
  22. Splitter,
  23. StandardEvent,
  24. ViewContainer,
  25. ViewContextType,
  26. WeekNumberContainer,
  27. addDurations,
  28. asRoughMs,
  29. binarySearch,
  30. buildEntryKey,
  31. buildEventRangeKey,
  32. buildIsoString,
  33. buildNavLinkAttrs,
  34. computeEarliestSegStart,
  35. createDuration,
  36. createFormatter,
  37. createPlugin,
  38. diffDays,
  39. formatIsoTimeString,
  40. getEntrySpanEnd,
  41. getSegMeta,
  42. getStickyFooterScrollbar,
  43. getStickyHeaderDates,
  44. groupIntersectingEntries,
  45. hasBgRendering,
  46. hasCustomDayCellContent,
  47. injectStyles,
  48. intersectRanges,
  49. memoize,
  50. multiplyDuration,
  51. rangeContainsMarker,
  52. renderFill,
  53. renderScrollShim,
  54. sortEventSegs,
  55. startOfDay,
  56. wholeDivideDurations
  57. } from "./chunk-QH2VTIUN.js";
  58. import {
  59. _,
  60. d,
  61. y
  62. } from "./chunk-PTVH4XAB.js";
  63. import "./chunk-2LSFTFF7.js";
  64. // node_modules/.pnpm/@fullcalendar+timegrid@6.1.14_@fullcalendar+core@6.1.14/node_modules/@fullcalendar/timegrid/internal.js
  65. var AllDaySplitter = class extends Splitter {
  66. getKeyInfo() {
  67. return {
  68. allDay: {},
  69. timed: {}
  70. };
  71. }
  72. getKeysForDateSpan(dateSpan) {
  73. if (dateSpan.allDay) {
  74. return ["allDay"];
  75. }
  76. return ["timed"];
  77. }
  78. getKeysForEventDef(eventDef) {
  79. if (!eventDef.allDay) {
  80. return ["timed"];
  81. }
  82. if (hasBgRendering(eventDef)) {
  83. return ["timed", "allDay"];
  84. }
  85. return ["allDay"];
  86. }
  87. };
  88. var DEFAULT_SLAT_LABEL_FORMAT = createFormatter({
  89. hour: "numeric",
  90. minute: "2-digit",
  91. omitZeroMinute: true,
  92. meridiem: "short"
  93. });
  94. function TimeColsAxisCell(props) {
  95. let classNames = [
  96. "fc-timegrid-slot",
  97. "fc-timegrid-slot-label",
  98. props.isLabeled ? "fc-scrollgrid-shrink" : "fc-timegrid-slot-minor"
  99. ];
  100. return y(ViewContextType.Consumer, null, (context) => {
  101. if (!props.isLabeled) {
  102. return y("td", { className: classNames.join(" "), "data-time": props.isoTimeStr });
  103. }
  104. let { dateEnv, options, viewApi } = context;
  105. let labelFormat = (
  106. // TODO: fully pre-parse
  107. options.slotLabelFormat == null ? DEFAULT_SLAT_LABEL_FORMAT : Array.isArray(options.slotLabelFormat) ? createFormatter(options.slotLabelFormat[0]) : createFormatter(options.slotLabelFormat)
  108. );
  109. let renderProps = {
  110. level: 0,
  111. time: props.time,
  112. date: dateEnv.toDate(props.date),
  113. view: viewApi,
  114. text: dateEnv.format(props.date, labelFormat)
  115. };
  116. return y(ContentContainer, { elTag: "td", elClasses: classNames, elAttrs: {
  117. "data-time": props.isoTimeStr
  118. }, renderProps, generatorName: "slotLabelContent", customGenerator: options.slotLabelContent, defaultGenerator: renderInnerContent, classNameGenerator: options.slotLabelClassNames, didMount: options.slotLabelDidMount, willUnmount: options.slotLabelWillUnmount }, (InnerContent) => y(
  119. "div",
  120. { className: "fc-timegrid-slot-label-frame fc-scrollgrid-shrink-frame" },
  121. y(InnerContent, { elTag: "div", elClasses: [
  122. "fc-timegrid-slot-label-cushion",
  123. "fc-scrollgrid-shrink-cushion"
  124. ] })
  125. ));
  126. });
  127. }
  128. function renderInnerContent(props) {
  129. return props.text;
  130. }
  131. var TimeBodyAxis = class extends BaseComponent {
  132. render() {
  133. return this.props.slatMetas.map((slatMeta) => y(
  134. "tr",
  135. { key: slatMeta.key },
  136. y(TimeColsAxisCell, Object.assign({}, slatMeta))
  137. ));
  138. }
  139. };
  140. var DEFAULT_WEEK_NUM_FORMAT = createFormatter({ week: "short" });
  141. var AUTO_ALL_DAY_MAX_EVENT_ROWS = 5;
  142. var TimeColsView = class extends DateComponent {
  143. constructor() {
  144. super(...arguments);
  145. this.allDaySplitter = new AllDaySplitter();
  146. this.headerElRef = d();
  147. this.rootElRef = d();
  148. this.scrollerElRef = d();
  149. this.state = {
  150. slatCoords: null
  151. };
  152. this.handleScrollTopRequest = (scrollTop) => {
  153. let scrollerEl = this.scrollerElRef.current;
  154. if (scrollerEl) {
  155. scrollerEl.scrollTop = scrollTop;
  156. }
  157. };
  158. this.renderHeadAxis = (rowKey, frameHeight = "") => {
  159. let { options } = this.context;
  160. let { dateProfile } = this.props;
  161. let range = dateProfile.renderRange;
  162. let dayCnt = diffDays(range.start, range.end);
  163. let navLinkAttrs = dayCnt === 1 ? buildNavLinkAttrs(this.context, range.start, "week") : {};
  164. if (options.weekNumbers && rowKey === "day") {
  165. return y(WeekNumberContainer, { elTag: "th", elClasses: [
  166. "fc-timegrid-axis",
  167. "fc-scrollgrid-shrink"
  168. ], elAttrs: {
  169. "aria-hidden": true
  170. }, date: range.start, defaultFormat: DEFAULT_WEEK_NUM_FORMAT }, (InnerContent) => y(
  171. "div",
  172. { className: [
  173. "fc-timegrid-axis-frame",
  174. "fc-scrollgrid-shrink-frame",
  175. "fc-timegrid-axis-frame-liquid"
  176. ].join(" "), style: { height: frameHeight } },
  177. y(InnerContent, { elTag: "a", elClasses: [
  178. "fc-timegrid-axis-cushion",
  179. "fc-scrollgrid-shrink-cushion",
  180. "fc-scrollgrid-sync-inner"
  181. ], elAttrs: navLinkAttrs })
  182. ));
  183. }
  184. return y(
  185. "th",
  186. { "aria-hidden": true, className: "fc-timegrid-axis" },
  187. y("div", { className: "fc-timegrid-axis-frame", style: { height: frameHeight } })
  188. );
  189. };
  190. this.renderTableRowAxis = (rowHeight) => {
  191. let { options, viewApi } = this.context;
  192. let renderProps = {
  193. text: options.allDayText,
  194. view: viewApi
  195. };
  196. return (
  197. // TODO: make reusable hook. used in list view too
  198. y(ContentContainer, { elTag: "td", elClasses: [
  199. "fc-timegrid-axis",
  200. "fc-scrollgrid-shrink"
  201. ], elAttrs: {
  202. "aria-hidden": true
  203. }, renderProps, generatorName: "allDayContent", customGenerator: options.allDayContent, defaultGenerator: renderAllDayInner, classNameGenerator: options.allDayClassNames, didMount: options.allDayDidMount, willUnmount: options.allDayWillUnmount }, (InnerContent) => y(
  204. "div",
  205. { className: [
  206. "fc-timegrid-axis-frame",
  207. "fc-scrollgrid-shrink-frame",
  208. rowHeight == null ? " fc-timegrid-axis-frame-liquid" : ""
  209. ].join(" "), style: { height: rowHeight } },
  210. y(InnerContent, { elTag: "span", elClasses: [
  211. "fc-timegrid-axis-cushion",
  212. "fc-scrollgrid-shrink-cushion",
  213. "fc-scrollgrid-sync-inner"
  214. ] })
  215. ))
  216. );
  217. };
  218. this.handleSlatCoords = (slatCoords) => {
  219. this.setState({ slatCoords });
  220. };
  221. }
  222. // rendering
  223. // ----------------------------------------------------------------------------------------------------
  224. renderSimpleLayout(headerRowContent, allDayContent, timeContent) {
  225. let { context, props } = this;
  226. let sections = [];
  227. let stickyHeaderDates = getStickyHeaderDates(context.options);
  228. if (headerRowContent) {
  229. sections.push({
  230. type: "header",
  231. key: "header",
  232. isSticky: stickyHeaderDates,
  233. chunk: {
  234. elRef: this.headerElRef,
  235. tableClassName: "fc-col-header",
  236. rowContent: headerRowContent
  237. }
  238. });
  239. }
  240. if (allDayContent) {
  241. sections.push({
  242. type: "body",
  243. key: "all-day",
  244. chunk: { content: allDayContent }
  245. });
  246. sections.push({
  247. type: "body",
  248. key: "all-day-divider",
  249. outerContent: (
  250. // TODO: rename to cellContent so don't need to define <tr>?
  251. y(
  252. "tr",
  253. { role: "presentation", className: "fc-scrollgrid-section" },
  254. y("td", { className: "fc-timegrid-divider " + context.theme.getClass("tableCellShaded") })
  255. )
  256. )
  257. });
  258. }
  259. sections.push({
  260. type: "body",
  261. key: "body",
  262. liquid: true,
  263. expandRows: Boolean(context.options.expandRows),
  264. chunk: {
  265. scrollerElRef: this.scrollerElRef,
  266. content: timeContent
  267. }
  268. });
  269. return y(
  270. ViewContainer,
  271. { elRef: this.rootElRef, elClasses: ["fc-timegrid"], viewSpec: context.viewSpec },
  272. y(SimpleScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [{ width: "shrink" }], sections })
  273. );
  274. }
  275. renderHScrollLayout(headerRowContent, allDayContent, timeContent, colCnt, dayMinWidth, slatMetas, slatCoords) {
  276. let ScrollGrid = this.context.pluginHooks.scrollGridImpl;
  277. if (!ScrollGrid) {
  278. throw new Error("No ScrollGrid implementation");
  279. }
  280. let { context, props } = this;
  281. let stickyHeaderDates = !props.forPrint && getStickyHeaderDates(context.options);
  282. let stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(context.options);
  283. let sections = [];
  284. if (headerRowContent) {
  285. sections.push({
  286. type: "header",
  287. key: "header",
  288. isSticky: stickyHeaderDates,
  289. syncRowHeights: true,
  290. chunks: [
  291. {
  292. key: "axis",
  293. rowContent: (arg) => y("tr", { role: "presentation" }, this.renderHeadAxis("day", arg.rowSyncHeights[0]))
  294. },
  295. {
  296. key: "cols",
  297. elRef: this.headerElRef,
  298. tableClassName: "fc-col-header",
  299. rowContent: headerRowContent
  300. }
  301. ]
  302. });
  303. }
  304. if (allDayContent) {
  305. sections.push({
  306. type: "body",
  307. key: "all-day",
  308. syncRowHeights: true,
  309. chunks: [
  310. {
  311. key: "axis",
  312. rowContent: (contentArg) => y("tr", { role: "presentation" }, this.renderTableRowAxis(contentArg.rowSyncHeights[0]))
  313. },
  314. {
  315. key: "cols",
  316. content: allDayContent
  317. }
  318. ]
  319. });
  320. sections.push({
  321. key: "all-day-divider",
  322. type: "body",
  323. outerContent: (
  324. // TODO: rename to cellContent so don't need to define <tr>?
  325. y(
  326. "tr",
  327. { role: "presentation", className: "fc-scrollgrid-section" },
  328. y("td", { colSpan: 2, className: "fc-timegrid-divider " + context.theme.getClass("tableCellShaded") })
  329. )
  330. )
  331. });
  332. }
  333. let isNowIndicator = context.options.nowIndicator;
  334. sections.push({
  335. type: "body",
  336. key: "body",
  337. liquid: true,
  338. expandRows: Boolean(context.options.expandRows),
  339. chunks: [
  340. {
  341. key: "axis",
  342. content: (arg) => (
  343. // TODO: make this now-indicator arrow more DRY with TimeColsContent
  344. y(
  345. "div",
  346. { className: "fc-timegrid-axis-chunk" },
  347. y(
  348. "table",
  349. { "aria-hidden": true, style: { height: arg.expandRows ? arg.clientHeight : "" } },
  350. arg.tableColGroupNode,
  351. y(
  352. "tbody",
  353. null,
  354. y(TimeBodyAxis, { slatMetas })
  355. )
  356. ),
  357. y(
  358. "div",
  359. { className: "fc-timegrid-now-indicator-container" },
  360. y(NowTimer, {
  361. unit: isNowIndicator ? "minute" : "day"
  362. /* hacky */
  363. }, (nowDate) => {
  364. let nowIndicatorTop = isNowIndicator && slatCoords && slatCoords.safeComputeTop(nowDate);
  365. if (typeof nowIndicatorTop === "number") {
  366. return y(NowIndicatorContainer, { elClasses: ["fc-timegrid-now-indicator-arrow"], elStyle: { top: nowIndicatorTop }, isAxis: true, date: nowDate });
  367. }
  368. return null;
  369. })
  370. )
  371. )
  372. )
  373. },
  374. {
  375. key: "cols",
  376. scrollerElRef: this.scrollerElRef,
  377. content: timeContent
  378. }
  379. ]
  380. });
  381. if (stickyFooterScrollbar) {
  382. sections.push({
  383. key: "footer",
  384. type: "footer",
  385. isSticky: true,
  386. chunks: [
  387. {
  388. key: "axis",
  389. content: renderScrollShim
  390. },
  391. {
  392. key: "cols",
  393. content: renderScrollShim
  394. }
  395. ]
  396. });
  397. }
  398. return y(
  399. ViewContainer,
  400. { elRef: this.rootElRef, elClasses: ["fc-timegrid"], viewSpec: context.viewSpec },
  401. y(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, forPrint: props.forPrint, collapsibleWidth: false, colGroups: [
  402. { width: "shrink", cols: [{ width: "shrink" }] },
  403. { cols: [{ span: colCnt, minWidth: dayMinWidth }] }
  404. ], sections })
  405. );
  406. }
  407. /* Dimensions
  408. ------------------------------------------------------------------------------------------------------------------*/
  409. getAllDayMaxEventProps() {
  410. let { dayMaxEvents, dayMaxEventRows } = this.context.options;
  411. if (dayMaxEvents === true || dayMaxEventRows === true) {
  412. dayMaxEvents = void 0;
  413. dayMaxEventRows = AUTO_ALL_DAY_MAX_EVENT_ROWS;
  414. }
  415. return { dayMaxEvents, dayMaxEventRows };
  416. }
  417. };
  418. function renderAllDayInner(renderProps) {
  419. return renderProps.text;
  420. }
  421. var TimeColsSlatsCoords = class {
  422. constructor(positions, dateProfile, slotDuration) {
  423. this.positions = positions;
  424. this.dateProfile = dateProfile;
  425. this.slotDuration = slotDuration;
  426. }
  427. safeComputeTop(date) {
  428. let { dateProfile } = this;
  429. if (rangeContainsMarker(dateProfile.currentRange, date)) {
  430. let startOfDayDate = startOfDay(date);
  431. let timeMs = date.valueOf() - startOfDayDate.valueOf();
  432. if (timeMs >= asRoughMs(dateProfile.slotMinTime) && timeMs < asRoughMs(dateProfile.slotMaxTime)) {
  433. return this.computeTimeTop(createDuration(timeMs));
  434. }
  435. }
  436. return null;
  437. }
  438. // Computes the top coordinate, relative to the bounds of the grid, of the given date.
  439. // A `startOfDayDate` must be given for avoiding ambiguity over how to treat midnight.
  440. computeDateTop(when, startOfDayDate) {
  441. if (!startOfDayDate) {
  442. startOfDayDate = startOfDay(when);
  443. }
  444. return this.computeTimeTop(createDuration(when.valueOf() - startOfDayDate.valueOf()));
  445. }
  446. // Computes the top coordinate, relative to the bounds of the grid, of the given time (a Duration).
  447. // This is a makeshify way to compute the time-top. Assumes all slatMetas dates are uniform.
  448. // Eventually allow computation with arbirary slat dates.
  449. computeTimeTop(duration) {
  450. let { positions, dateProfile } = this;
  451. let len = positions.els.length;
  452. let slatCoverage = (duration.milliseconds - asRoughMs(dateProfile.slotMinTime)) / asRoughMs(this.slotDuration);
  453. let slatIndex;
  454. let slatRemainder;
  455. slatCoverage = Math.max(0, slatCoverage);
  456. slatCoverage = Math.min(len, slatCoverage);
  457. slatIndex = Math.floor(slatCoverage);
  458. slatIndex = Math.min(slatIndex, len - 1);
  459. slatRemainder = slatCoverage - slatIndex;
  460. return positions.tops[slatIndex] + positions.getHeight(slatIndex) * slatRemainder;
  461. }
  462. };
  463. var TimeColsSlatsBody = class extends BaseComponent {
  464. render() {
  465. let { props, context } = this;
  466. let { options } = context;
  467. let { slatElRefs } = props;
  468. return y("tbody", null, props.slatMetas.map((slatMeta, i) => {
  469. let renderProps = {
  470. time: slatMeta.time,
  471. date: context.dateEnv.toDate(slatMeta.date),
  472. view: context.viewApi
  473. };
  474. return y(
  475. "tr",
  476. { key: slatMeta.key, ref: slatElRefs.createRef(slatMeta.key) },
  477. props.axis && y(TimeColsAxisCell, Object.assign({}, slatMeta)),
  478. y(ContentContainer, { elTag: "td", elClasses: [
  479. "fc-timegrid-slot",
  480. "fc-timegrid-slot-lane",
  481. !slatMeta.isLabeled && "fc-timegrid-slot-minor"
  482. ], elAttrs: {
  483. "data-time": slatMeta.isoTimeStr
  484. }, renderProps, generatorName: "slotLaneContent", customGenerator: options.slotLaneContent, classNameGenerator: options.slotLaneClassNames, didMount: options.slotLaneDidMount, willUnmount: options.slotLaneWillUnmount })
  485. );
  486. }));
  487. }
  488. };
  489. var TimeColsSlats = class extends BaseComponent {
  490. constructor() {
  491. super(...arguments);
  492. this.rootElRef = d();
  493. this.slatElRefs = new RefMap();
  494. }
  495. render() {
  496. let { props, context } = this;
  497. return y(
  498. "div",
  499. { ref: this.rootElRef, className: "fc-timegrid-slots" },
  500. y(
  501. "table",
  502. { "aria-hidden": true, className: context.theme.getClass("table"), style: {
  503. minWidth: props.tableMinWidth,
  504. width: props.clientWidth,
  505. height: props.minHeight
  506. } },
  507. props.tableColGroupNode,
  508. y(TimeColsSlatsBody, { slatElRefs: this.slatElRefs, axis: props.axis, slatMetas: props.slatMetas })
  509. )
  510. );
  511. }
  512. componentDidMount() {
  513. this.updateSizing();
  514. }
  515. componentDidUpdate() {
  516. this.updateSizing();
  517. }
  518. componentWillUnmount() {
  519. if (this.props.onCoords) {
  520. this.props.onCoords(null);
  521. }
  522. }
  523. updateSizing() {
  524. let { context, props } = this;
  525. if (props.onCoords && props.clientWidth !== null) {
  526. let rootEl = this.rootElRef.current;
  527. if (rootEl.offsetHeight) {
  528. props.onCoords(new TimeColsSlatsCoords(new PositionCache(this.rootElRef.current, collectSlatEls(this.slatElRefs.currentMap, props.slatMetas), false, true), this.props.dateProfile, context.options.slotDuration));
  529. }
  530. }
  531. }
  532. };
  533. function collectSlatEls(elMap, slatMetas) {
  534. return slatMetas.map((slatMeta) => elMap[slatMeta.key]);
  535. }
  536. function splitSegsByCol(segs, colCnt) {
  537. let segsByCol = [];
  538. let i;
  539. for (i = 0; i < colCnt; i += 1) {
  540. segsByCol.push([]);
  541. }
  542. if (segs) {
  543. for (i = 0; i < segs.length; i += 1) {
  544. segsByCol[segs[i].col].push(segs[i]);
  545. }
  546. }
  547. return segsByCol;
  548. }
  549. function splitInteractionByCol(ui, colCnt) {
  550. let byRow = [];
  551. if (!ui) {
  552. for (let i = 0; i < colCnt; i += 1) {
  553. byRow[i] = null;
  554. }
  555. } else {
  556. for (let i = 0; i < colCnt; i += 1) {
  557. byRow[i] = {
  558. affectedInstances: ui.affectedInstances,
  559. isEvent: ui.isEvent,
  560. segs: []
  561. };
  562. }
  563. for (let seg of ui.segs) {
  564. byRow[seg.col].segs.push(seg);
  565. }
  566. }
  567. return byRow;
  568. }
  569. var TimeColMoreLink = class extends BaseComponent {
  570. render() {
  571. let { props } = this;
  572. return y(MoreLinkContainer, { elClasses: ["fc-timegrid-more-link"], elStyle: {
  573. top: props.top,
  574. bottom: props.bottom
  575. }, allDayDate: null, moreCnt: props.hiddenSegs.length, allSegs: props.hiddenSegs, hiddenSegs: props.hiddenSegs, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, todayRange: props.todayRange, popoverContent: () => renderPlainFgSegs(props.hiddenSegs, props), defaultGenerator: renderMoreLinkInner, forceTimed: true }, (InnerContent) => y(InnerContent, { elTag: "div", elClasses: ["fc-timegrid-more-link-inner", "fc-sticky"] }));
  576. }
  577. };
  578. function renderMoreLinkInner(props) {
  579. return props.shortText;
  580. }
  581. function buildPositioning(segInputs, strictOrder, maxStackCnt) {
  582. let hierarchy = new SegHierarchy();
  583. if (strictOrder != null) {
  584. hierarchy.strictOrder = strictOrder;
  585. }
  586. if (maxStackCnt != null) {
  587. hierarchy.maxStackCnt = maxStackCnt;
  588. }
  589. let hiddenEntries = hierarchy.addSegs(segInputs);
  590. let hiddenGroups = groupIntersectingEntries(hiddenEntries);
  591. let web = buildWeb(hierarchy);
  592. web = stretchWeb(web, 1);
  593. let segRects = webToRects(web);
  594. return { segRects, hiddenGroups };
  595. }
  596. function buildWeb(hierarchy) {
  597. const { entriesByLevel } = hierarchy;
  598. const buildNode = cacheable((level, lateral) => level + ":" + lateral, (level, lateral) => {
  599. let siblingRange = findNextLevelSegs(hierarchy, level, lateral);
  600. let nextLevelRes = buildNodes(siblingRange, buildNode);
  601. let entry = entriesByLevel[level][lateral];
  602. return [
  603. Object.assign(Object.assign({}, entry), { nextLevelNodes: nextLevelRes[0] }),
  604. entry.thickness + nextLevelRes[1]
  605. // the pressure builds
  606. ];
  607. });
  608. return buildNodes(entriesByLevel.length ? { level: 0, lateralStart: 0, lateralEnd: entriesByLevel[0].length } : null, buildNode)[0];
  609. }
  610. function buildNodes(siblingRange, buildNode) {
  611. if (!siblingRange) {
  612. return [[], 0];
  613. }
  614. let { level, lateralStart, lateralEnd } = siblingRange;
  615. let lateral = lateralStart;
  616. let pairs = [];
  617. while (lateral < lateralEnd) {
  618. pairs.push(buildNode(level, lateral));
  619. lateral += 1;
  620. }
  621. pairs.sort(cmpDescPressures);
  622. return [
  623. pairs.map(extractNode),
  624. pairs[0][1]
  625. // first item's pressure
  626. ];
  627. }
  628. function cmpDescPressures(a, b) {
  629. return b[1] - a[1];
  630. }
  631. function extractNode(a) {
  632. return a[0];
  633. }
  634. function findNextLevelSegs(hierarchy, subjectLevel, subjectLateral) {
  635. let { levelCoords, entriesByLevel } = hierarchy;
  636. let subjectEntry = entriesByLevel[subjectLevel][subjectLateral];
  637. let afterSubject = levelCoords[subjectLevel] + subjectEntry.thickness;
  638. let levelCnt = levelCoords.length;
  639. let level = subjectLevel;
  640. for (; level < levelCnt && levelCoords[level] < afterSubject; level += 1)
  641. ;
  642. for (; level < levelCnt; level += 1) {
  643. let entries = entriesByLevel[level];
  644. let entry;
  645. let searchIndex = binarySearch(entries, subjectEntry.span.start, getEntrySpanEnd);
  646. let lateralStart = searchIndex[0] + searchIndex[1];
  647. let lateralEnd = lateralStart;
  648. while (
  649. // loop through entries that horizontally intersect
  650. (entry = entries[lateralEnd]) && // but not past the whole seg list
  651. entry.span.start < subjectEntry.span.end
  652. ) {
  653. lateralEnd += 1;
  654. }
  655. if (lateralStart < lateralEnd) {
  656. return { level, lateralStart, lateralEnd };
  657. }
  658. }
  659. return null;
  660. }
  661. function stretchWeb(topLevelNodes, totalThickness) {
  662. const stretchNode = cacheable((node, startCoord, prevThickness) => buildEntryKey(node), (node, startCoord, prevThickness) => {
  663. let { nextLevelNodes, thickness } = node;
  664. let allThickness = thickness + prevThickness;
  665. let thicknessFraction = thickness / allThickness;
  666. let endCoord;
  667. let newChildren = [];
  668. if (!nextLevelNodes.length) {
  669. endCoord = totalThickness;
  670. } else {
  671. for (let childNode of nextLevelNodes) {
  672. if (endCoord === void 0) {
  673. let res = stretchNode(childNode, startCoord, allThickness);
  674. endCoord = res[0];
  675. newChildren.push(res[1]);
  676. } else {
  677. let res = stretchNode(childNode, endCoord, 0);
  678. newChildren.push(res[1]);
  679. }
  680. }
  681. }
  682. let newThickness = (endCoord - startCoord) * thicknessFraction;
  683. return [endCoord - newThickness, Object.assign(Object.assign({}, node), { thickness: newThickness, nextLevelNodes: newChildren })];
  684. });
  685. return topLevelNodes.map((node) => stretchNode(node, 0, 0)[1]);
  686. }
  687. function webToRects(topLevelNodes) {
  688. let rects = [];
  689. const processNode = cacheable((node, levelCoord, stackDepth) => buildEntryKey(node), (node, levelCoord, stackDepth) => {
  690. let rect = Object.assign(Object.assign({}, node), {
  691. levelCoord,
  692. stackDepth,
  693. stackForward: 0
  694. });
  695. rects.push(rect);
  696. return rect.stackForward = processNodes(node.nextLevelNodes, levelCoord + node.thickness, stackDepth + 1) + 1;
  697. });
  698. function processNodes(nodes, levelCoord, stackDepth) {
  699. let stackForward = 0;
  700. for (let node of nodes) {
  701. stackForward = Math.max(processNode(node, levelCoord, stackDepth), stackForward);
  702. }
  703. return stackForward;
  704. }
  705. processNodes(topLevelNodes, 0, 0);
  706. return rects;
  707. }
  708. function cacheable(keyFunc, workFunc) {
  709. const cache = {};
  710. return (...args) => {
  711. let key = keyFunc(...args);
  712. return key in cache ? cache[key] : cache[key] = workFunc(...args);
  713. };
  714. }
  715. function computeSegVCoords(segs, colDate, slatCoords = null, eventMinHeight = 0) {
  716. let vcoords = [];
  717. if (slatCoords) {
  718. for (let i = 0; i < segs.length; i += 1) {
  719. let seg = segs[i];
  720. let spanStart = slatCoords.computeDateTop(seg.start, colDate);
  721. let spanEnd = Math.max(
  722. spanStart + (eventMinHeight || 0),
  723. // :(
  724. slatCoords.computeDateTop(seg.end, colDate)
  725. );
  726. vcoords.push({
  727. start: Math.round(spanStart),
  728. end: Math.round(spanEnd)
  729. //
  730. });
  731. }
  732. }
  733. return vcoords;
  734. }
  735. function computeFgSegPlacements(segs, segVCoords, eventOrderStrict, eventMaxStack) {
  736. let segInputs = [];
  737. let dumbSegs = [];
  738. for (let i = 0; i < segs.length; i += 1) {
  739. let vcoords = segVCoords[i];
  740. if (vcoords) {
  741. segInputs.push({
  742. index: i,
  743. thickness: 1,
  744. span: vcoords
  745. });
  746. } else {
  747. dumbSegs.push(segs[i]);
  748. }
  749. }
  750. let { segRects, hiddenGroups } = buildPositioning(segInputs, eventOrderStrict, eventMaxStack);
  751. let segPlacements = [];
  752. for (let segRect of segRects) {
  753. segPlacements.push({
  754. seg: segs[segRect.index],
  755. rect: segRect
  756. });
  757. }
  758. for (let dumbSeg of dumbSegs) {
  759. segPlacements.push({ seg: dumbSeg, rect: null });
  760. }
  761. return { segPlacements, hiddenGroups };
  762. }
  763. var DEFAULT_TIME_FORMAT = createFormatter({
  764. hour: "numeric",
  765. minute: "2-digit",
  766. meridiem: false
  767. });
  768. var TimeColEvent = class extends BaseComponent {
  769. render() {
  770. return y(StandardEvent, Object.assign({}, this.props, { elClasses: [
  771. "fc-timegrid-event",
  772. "fc-v-event",
  773. this.props.isShort && "fc-timegrid-event-short"
  774. ], defaultTimeFormat: DEFAULT_TIME_FORMAT }));
  775. }
  776. };
  777. var TimeCol = class extends BaseComponent {
  778. constructor() {
  779. super(...arguments);
  780. this.sortEventSegs = memoize(sortEventSegs);
  781. }
  782. // TODO: memoize event-placement?
  783. render() {
  784. let { props, context } = this;
  785. let { options } = context;
  786. let isSelectMirror = options.selectMirror;
  787. let mirrorSegs = (
  788. // yuck
  789. props.eventDrag && props.eventDrag.segs || props.eventResize && props.eventResize.segs || isSelectMirror && props.dateSelectionSegs || []
  790. );
  791. let interactionAffectedInstances = (
  792. // TODO: messy way to compute this
  793. props.eventDrag && props.eventDrag.affectedInstances || props.eventResize && props.eventResize.affectedInstances || {}
  794. );
  795. let sortedFgSegs = this.sortEventSegs(props.fgEventSegs, options.eventOrder);
  796. return y(DayCellContainer, { elTag: "td", elRef: props.elRef, elClasses: [
  797. "fc-timegrid-col",
  798. ...props.extraClassNames || []
  799. ], elAttrs: Object.assign({ role: "gridcell" }, props.extraDataAttrs), date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, extraRenderProps: props.extraRenderProps }, (InnerContent) => y(
  800. "div",
  801. { className: "fc-timegrid-col-frame" },
  802. y(
  803. "div",
  804. { className: "fc-timegrid-col-bg" },
  805. this.renderFillSegs(props.businessHourSegs, "non-business"),
  806. this.renderFillSegs(props.bgEventSegs, "bg-event"),
  807. this.renderFillSegs(props.dateSelectionSegs, "highlight")
  808. ),
  809. y("div", { className: "fc-timegrid-col-events" }, this.renderFgSegs(sortedFgSegs, interactionAffectedInstances, false, false, false)),
  810. y("div", { className: "fc-timegrid-col-events" }, this.renderFgSegs(mirrorSegs, {}, Boolean(props.eventDrag), Boolean(props.eventResize), Boolean(isSelectMirror), "mirror")),
  811. y("div", { className: "fc-timegrid-now-indicator-container" }, this.renderNowIndicator(props.nowIndicatorSegs)),
  812. hasCustomDayCellContent(options) && y(InnerContent, { elTag: "div", elClasses: ["fc-timegrid-col-misc"] })
  813. ));
  814. }
  815. renderFgSegs(sortedFgSegs, segIsInvisible, isDragging, isResizing, isDateSelecting, forcedKey) {
  816. let { props } = this;
  817. if (props.forPrint) {
  818. return renderPlainFgSegs(sortedFgSegs, props);
  819. }
  820. return this.renderPositionedFgSegs(sortedFgSegs, segIsInvisible, isDragging, isResizing, isDateSelecting, forcedKey);
  821. }
  822. renderPositionedFgSegs(segs, segIsInvisible, isDragging, isResizing, isDateSelecting, forcedKey) {
  823. let { eventMaxStack, eventShortHeight, eventOrderStrict, eventMinHeight } = this.context.options;
  824. let { date, slatCoords, eventSelection, todayRange, nowDate } = this.props;
  825. let isMirror = isDragging || isResizing || isDateSelecting;
  826. let segVCoords = computeSegVCoords(segs, date, slatCoords, eventMinHeight);
  827. let { segPlacements, hiddenGroups } = computeFgSegPlacements(segs, segVCoords, eventOrderStrict, eventMaxStack);
  828. return y(
  829. _,
  830. null,
  831. this.renderHiddenGroups(hiddenGroups, segs),
  832. segPlacements.map((segPlacement) => {
  833. let { seg, rect } = segPlacement;
  834. let instanceId = seg.eventRange.instance.instanceId;
  835. let isVisible = isMirror || Boolean(!segIsInvisible[instanceId] && rect);
  836. let vStyle = computeSegVStyle(rect && rect.span);
  837. let hStyle = !isMirror && rect ? this.computeSegHStyle(rect) : { left: 0, right: 0 };
  838. let isInset = Boolean(rect) && rect.stackForward > 0;
  839. let isShort = Boolean(rect) && rect.span.end - rect.span.start < eventShortHeight;
  840. return y(
  841. "div",
  842. { className: "fc-timegrid-event-harness" + (isInset ? " fc-timegrid-event-harness-inset" : ""), key: forcedKey || instanceId, style: Object.assign(Object.assign({ visibility: isVisible ? "" : "hidden" }, vStyle), hStyle) },
  843. y(TimeColEvent, Object.assign({ seg, isDragging, isResizing, isDateSelecting, isSelected: instanceId === eventSelection, isShort }, getSegMeta(seg, todayRange, nowDate)))
  844. );
  845. })
  846. );
  847. }
  848. // will already have eventMinHeight applied because segInputs already had it
  849. renderHiddenGroups(hiddenGroups, segs) {
  850. let { extraDateSpan, dateProfile, todayRange, nowDate, eventSelection, eventDrag, eventResize } = this.props;
  851. return y(_, null, hiddenGroups.map((hiddenGroup) => {
  852. let positionCss = computeSegVStyle(hiddenGroup.span);
  853. let hiddenSegs = compileSegsFromEntries(hiddenGroup.entries, segs);
  854. return y(TimeColMoreLink, { key: buildIsoString(computeEarliestSegStart(hiddenSegs)), hiddenSegs, top: positionCss.top, bottom: positionCss.bottom, extraDateSpan, dateProfile, todayRange, nowDate, eventSelection, eventDrag, eventResize });
  855. }));
  856. }
  857. renderFillSegs(segs, fillType) {
  858. let { props, context } = this;
  859. let segVCoords = computeSegVCoords(segs, props.date, props.slatCoords, context.options.eventMinHeight);
  860. let children = segVCoords.map((vcoords, i) => {
  861. let seg = segs[i];
  862. return y("div", { key: buildEventRangeKey(seg.eventRange), className: "fc-timegrid-bg-harness", style: computeSegVStyle(vcoords) }, fillType === "bg-event" ? y(BgEvent, Object.assign({ seg }, getSegMeta(seg, props.todayRange, props.nowDate))) : renderFill(fillType));
  863. });
  864. return y(_, null, children);
  865. }
  866. renderNowIndicator(segs) {
  867. let { slatCoords, date } = this.props;
  868. if (!slatCoords) {
  869. return null;
  870. }
  871. return segs.map((seg, i) => y(
  872. NowIndicatorContainer,
  873. {
  874. // key doesn't matter. will only ever be one
  875. key: i,
  876. elClasses: ["fc-timegrid-now-indicator-line"],
  877. elStyle: {
  878. top: slatCoords.computeDateTop(seg.start, date)
  879. },
  880. isAxis: false,
  881. date
  882. }
  883. ));
  884. }
  885. computeSegHStyle(segHCoords) {
  886. let { isRtl, options } = this.context;
  887. let shouldOverlap = options.slotEventOverlap;
  888. let nearCoord = segHCoords.levelCoord;
  889. let farCoord = segHCoords.levelCoord + segHCoords.thickness;
  890. let left;
  891. let right;
  892. if (shouldOverlap) {
  893. farCoord = Math.min(1, nearCoord + (farCoord - nearCoord) * 2);
  894. }
  895. if (isRtl) {
  896. left = 1 - farCoord;
  897. right = nearCoord;
  898. } else {
  899. left = nearCoord;
  900. right = 1 - farCoord;
  901. }
  902. let props = {
  903. zIndex: segHCoords.stackDepth + 1,
  904. left: left * 100 + "%",
  905. right: right * 100 + "%"
  906. };
  907. if (shouldOverlap && !segHCoords.stackForward) {
  908. props[isRtl ? "marginLeft" : "marginRight"] = 10 * 2;
  909. }
  910. return props;
  911. }
  912. };
  913. function renderPlainFgSegs(sortedFgSegs, { todayRange, nowDate, eventSelection, eventDrag, eventResize }) {
  914. let hiddenInstances = (eventDrag ? eventDrag.affectedInstances : null) || (eventResize ? eventResize.affectedInstances : null) || {};
  915. return y(_, null, sortedFgSegs.map((seg) => {
  916. let instanceId = seg.eventRange.instance.instanceId;
  917. return y(
  918. "div",
  919. { key: instanceId, style: { visibility: hiddenInstances[instanceId] ? "hidden" : "" } },
  920. y(TimeColEvent, Object.assign({ seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === eventSelection, isShort: false }, getSegMeta(seg, todayRange, nowDate)))
  921. );
  922. }));
  923. }
  924. function computeSegVStyle(segVCoords) {
  925. if (!segVCoords) {
  926. return { top: "", bottom: "" };
  927. }
  928. return {
  929. top: segVCoords.start,
  930. bottom: -segVCoords.end
  931. };
  932. }
  933. function compileSegsFromEntries(segEntries, allSegs) {
  934. return segEntries.map((segEntry) => allSegs[segEntry.index]);
  935. }
  936. var TimeColsContent = class extends BaseComponent {
  937. constructor() {
  938. super(...arguments);
  939. this.splitFgEventSegs = memoize(splitSegsByCol);
  940. this.splitBgEventSegs = memoize(splitSegsByCol);
  941. this.splitBusinessHourSegs = memoize(splitSegsByCol);
  942. this.splitNowIndicatorSegs = memoize(splitSegsByCol);
  943. this.splitDateSelectionSegs = memoize(splitSegsByCol);
  944. this.splitEventDrag = memoize(splitInteractionByCol);
  945. this.splitEventResize = memoize(splitInteractionByCol);
  946. this.rootElRef = d();
  947. this.cellElRefs = new RefMap();
  948. }
  949. render() {
  950. let { props, context } = this;
  951. let nowIndicatorTop = context.options.nowIndicator && props.slatCoords && props.slatCoords.safeComputeTop(props.nowDate);
  952. let colCnt = props.cells.length;
  953. let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, colCnt);
  954. let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, colCnt);
  955. let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, colCnt);
  956. let nowIndicatorSegsByRow = this.splitNowIndicatorSegs(props.nowIndicatorSegs, colCnt);
  957. let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, colCnt);
  958. let eventDragByRow = this.splitEventDrag(props.eventDrag, colCnt);
  959. let eventResizeByRow = this.splitEventResize(props.eventResize, colCnt);
  960. return y(
  961. "div",
  962. { className: "fc-timegrid-cols", ref: this.rootElRef },
  963. y(
  964. "table",
  965. { role: "presentation", style: {
  966. minWidth: props.tableMinWidth,
  967. width: props.clientWidth
  968. } },
  969. props.tableColGroupNode,
  970. y(
  971. "tbody",
  972. { role: "presentation" },
  973. y(
  974. "tr",
  975. { role: "row" },
  976. props.axis && y(
  977. "td",
  978. { "aria-hidden": true, className: "fc-timegrid-col fc-timegrid-axis" },
  979. y(
  980. "div",
  981. { className: "fc-timegrid-col-frame" },
  982. y("div", { className: "fc-timegrid-now-indicator-container" }, typeof nowIndicatorTop === "number" && y(NowIndicatorContainer, { elClasses: ["fc-timegrid-now-indicator-arrow"], elStyle: { top: nowIndicatorTop }, isAxis: true, date: props.nowDate }))
  983. )
  984. ),
  985. props.cells.map((cell, i) => y(TimeCol, { key: cell.key, elRef: this.cellElRefs.createRef(cell.key), dateProfile: props.dateProfile, date: cell.date, nowDate: props.nowDate, todayRange: props.todayRange, extraRenderProps: cell.extraRenderProps, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames, extraDateSpan: cell.extraDateSpan, fgEventSegs: fgEventSegsByRow[i], bgEventSegs: bgEventSegsByRow[i], businessHourSegs: businessHourSegsByRow[i], nowIndicatorSegs: nowIndicatorSegsByRow[i], dateSelectionSegs: dateSelectionSegsByRow[i], eventDrag: eventDragByRow[i], eventResize: eventResizeByRow[i], slatCoords: props.slatCoords, eventSelection: props.eventSelection, forPrint: props.forPrint }))
  986. )
  987. )
  988. )
  989. );
  990. }
  991. componentDidMount() {
  992. this.updateCoords();
  993. }
  994. componentDidUpdate() {
  995. this.updateCoords();
  996. }
  997. updateCoords() {
  998. let { props } = this;
  999. if (props.onColCoords && props.clientWidth !== null) {
  1000. props.onColCoords(new PositionCache(
  1001. this.rootElRef.current,
  1002. collectCellEls(this.cellElRefs.currentMap, props.cells),
  1003. true,
  1004. // horizontal
  1005. false
  1006. ));
  1007. }
  1008. }
  1009. };
  1010. function collectCellEls(elMap, cells) {
  1011. return cells.map((cell) => elMap[cell.key]);
  1012. }
  1013. var TimeCols = class extends DateComponent {
  1014. constructor() {
  1015. super(...arguments);
  1016. this.processSlotOptions = memoize(processSlotOptions);
  1017. this.state = {
  1018. slatCoords: null
  1019. };
  1020. this.handleRootEl = (el) => {
  1021. if (el) {
  1022. this.context.registerInteractiveComponent(this, {
  1023. el,
  1024. isHitComboAllowed: this.props.isHitComboAllowed
  1025. });
  1026. } else {
  1027. this.context.unregisterInteractiveComponent(this);
  1028. }
  1029. };
  1030. this.handleScrollRequest = (request) => {
  1031. let { onScrollTopRequest } = this.props;
  1032. let { slatCoords } = this.state;
  1033. if (onScrollTopRequest && slatCoords) {
  1034. if (request.time) {
  1035. let top = slatCoords.computeTimeTop(request.time);
  1036. top = Math.ceil(top);
  1037. if (top) {
  1038. top += 1;
  1039. }
  1040. onScrollTopRequest(top);
  1041. }
  1042. return true;
  1043. }
  1044. return false;
  1045. };
  1046. this.handleColCoords = (colCoords) => {
  1047. this.colCoords = colCoords;
  1048. };
  1049. this.handleSlatCoords = (slatCoords) => {
  1050. this.setState({ slatCoords });
  1051. if (this.props.onSlatCoords) {
  1052. this.props.onSlatCoords(slatCoords);
  1053. }
  1054. };
  1055. }
  1056. render() {
  1057. let { props, state } = this;
  1058. return y(
  1059. "div",
  1060. { className: "fc-timegrid-body", ref: this.handleRootEl, style: {
  1061. // these props are important to give this wrapper correct dimensions for interactions
  1062. // TODO: if we set it here, can we avoid giving to inner tables?
  1063. width: props.clientWidth,
  1064. minWidth: props.tableMinWidth
  1065. } },
  1066. y(TimeColsSlats, { axis: props.axis, dateProfile: props.dateProfile, slatMetas: props.slatMetas, clientWidth: props.clientWidth, minHeight: props.expandRows ? props.clientHeight : "", tableMinWidth: props.tableMinWidth, tableColGroupNode: props.axis ? props.tableColGroupNode : null, onCoords: this.handleSlatCoords }),
  1067. y(TimeColsContent, { cells: props.cells, axis: props.axis, dateProfile: props.dateProfile, businessHourSegs: props.businessHourSegs, bgEventSegs: props.bgEventSegs, fgEventSegs: props.fgEventSegs, dateSelectionSegs: props.dateSelectionSegs, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange, nowDate: props.nowDate, nowIndicatorSegs: props.nowIndicatorSegs, clientWidth: props.clientWidth, tableMinWidth: props.tableMinWidth, tableColGroupNode: props.tableColGroupNode, slatCoords: state.slatCoords, onColCoords: this.handleColCoords, forPrint: props.forPrint })
  1068. );
  1069. }
  1070. componentDidMount() {
  1071. this.scrollResponder = this.context.createScrollResponder(this.handleScrollRequest);
  1072. }
  1073. componentDidUpdate(prevProps) {
  1074. this.scrollResponder.update(prevProps.dateProfile !== this.props.dateProfile);
  1075. }
  1076. componentWillUnmount() {
  1077. this.scrollResponder.detach();
  1078. }
  1079. queryHit(positionLeft, positionTop) {
  1080. let { dateEnv, options } = this.context;
  1081. let { colCoords } = this;
  1082. let { dateProfile } = this.props;
  1083. let { slatCoords } = this.state;
  1084. let { snapDuration, snapsPerSlot } = this.processSlotOptions(this.props.slotDuration, options.snapDuration);
  1085. let colIndex = colCoords.leftToIndex(positionLeft);
  1086. let slatIndex = slatCoords.positions.topToIndex(positionTop);
  1087. if (colIndex != null && slatIndex != null) {
  1088. let cell = this.props.cells[colIndex];
  1089. let slatTop = slatCoords.positions.tops[slatIndex];
  1090. let slatHeight = slatCoords.positions.getHeight(slatIndex);
  1091. let partial = (positionTop - slatTop) / slatHeight;
  1092. let localSnapIndex = Math.floor(partial * snapsPerSlot);
  1093. let snapIndex = slatIndex * snapsPerSlot + localSnapIndex;
  1094. let dayDate = this.props.cells[colIndex].date;
  1095. let time = addDurations(dateProfile.slotMinTime, multiplyDuration(snapDuration, snapIndex));
  1096. let start = dateEnv.add(dayDate, time);
  1097. let end = dateEnv.add(start, snapDuration);
  1098. return {
  1099. dateProfile,
  1100. dateSpan: Object.assign({ range: { start, end }, allDay: false }, cell.extraDateSpan),
  1101. dayEl: colCoords.els[colIndex],
  1102. rect: {
  1103. left: colCoords.lefts[colIndex],
  1104. right: colCoords.rights[colIndex],
  1105. top: slatTop,
  1106. bottom: slatTop + slatHeight
  1107. },
  1108. layer: 0
  1109. };
  1110. }
  1111. return null;
  1112. }
  1113. };
  1114. function processSlotOptions(slotDuration, snapDurationOverride) {
  1115. let snapDuration = snapDurationOverride || slotDuration;
  1116. let snapsPerSlot = wholeDivideDurations(slotDuration, snapDuration);
  1117. if (snapsPerSlot === null) {
  1118. snapDuration = slotDuration;
  1119. snapsPerSlot = 1;
  1120. }
  1121. return { snapDuration, snapsPerSlot };
  1122. }
  1123. var DayTimeColsSlicer = class extends Slicer {
  1124. sliceRange(range, dayRanges) {
  1125. let segs = [];
  1126. for (let col = 0; col < dayRanges.length; col += 1) {
  1127. let segRange = intersectRanges(range, dayRanges[col]);
  1128. if (segRange) {
  1129. segs.push({
  1130. start: segRange.start,
  1131. end: segRange.end,
  1132. isStart: segRange.start.valueOf() === range.start.valueOf(),
  1133. isEnd: segRange.end.valueOf() === range.end.valueOf(),
  1134. col
  1135. });
  1136. }
  1137. }
  1138. return segs;
  1139. }
  1140. };
  1141. var DayTimeCols = class extends DateComponent {
  1142. constructor() {
  1143. super(...arguments);
  1144. this.buildDayRanges = memoize(buildDayRanges);
  1145. this.slicer = new DayTimeColsSlicer();
  1146. this.timeColsRef = d();
  1147. }
  1148. render() {
  1149. let { props, context } = this;
  1150. let { dateProfile, dayTableModel } = props;
  1151. let { nowIndicator, nextDayThreshold } = context.options;
  1152. let dayRanges = this.buildDayRanges(dayTableModel, dateProfile, context.dateEnv);
  1153. return y(NowTimer, { unit: nowIndicator ? "minute" : "day" }, (nowDate, todayRange) => y(TimeCols, Object.assign({ ref: this.timeColsRef }, this.slicer.sliceProps(props, dateProfile, null, context, dayRanges), { forPrint: props.forPrint, axis: props.axis, dateProfile, slatMetas: props.slatMetas, slotDuration: props.slotDuration, cells: dayTableModel.cells[0], tableColGroupNode: props.tableColGroupNode, tableMinWidth: props.tableMinWidth, clientWidth: props.clientWidth, clientHeight: props.clientHeight, expandRows: props.expandRows, nowDate, nowIndicatorSegs: nowIndicator && this.slicer.sliceNowDate(nowDate, dateProfile, nextDayThreshold, context, dayRanges), todayRange, onScrollTopRequest: props.onScrollTopRequest, onSlatCoords: props.onSlatCoords })));
  1154. }
  1155. };
  1156. function buildDayRanges(dayTableModel, dateProfile, dateEnv) {
  1157. let ranges = [];
  1158. for (let date of dayTableModel.headerDates) {
  1159. ranges.push({
  1160. start: dateEnv.add(date, dateProfile.slotMinTime),
  1161. end: dateEnv.add(date, dateProfile.slotMaxTime)
  1162. });
  1163. }
  1164. return ranges;
  1165. }
  1166. var STOCK_SUB_DURATIONS = [
  1167. { hours: 1 },
  1168. { minutes: 30 },
  1169. { minutes: 15 },
  1170. { seconds: 30 },
  1171. { seconds: 15 }
  1172. ];
  1173. function buildSlatMetas(slotMinTime, slotMaxTime, explicitLabelInterval, slotDuration, dateEnv) {
  1174. let dayStart = /* @__PURE__ */ new Date(0);
  1175. let slatTime = slotMinTime;
  1176. let slatIterator = createDuration(0);
  1177. let labelInterval = explicitLabelInterval || computeLabelInterval(slotDuration);
  1178. let metas = [];
  1179. while (asRoughMs(slatTime) < asRoughMs(slotMaxTime)) {
  1180. let date = dateEnv.add(dayStart, slatTime);
  1181. let isLabeled = wholeDivideDurations(slatIterator, labelInterval) !== null;
  1182. metas.push({
  1183. date,
  1184. time: slatTime,
  1185. key: date.toISOString(),
  1186. isoTimeStr: formatIsoTimeString(date),
  1187. isLabeled
  1188. });
  1189. slatTime = addDurations(slatTime, slotDuration);
  1190. slatIterator = addDurations(slatIterator, slotDuration);
  1191. }
  1192. return metas;
  1193. }
  1194. function computeLabelInterval(slotDuration) {
  1195. let i;
  1196. let labelInterval;
  1197. let slotsPerLabel;
  1198. for (i = STOCK_SUB_DURATIONS.length - 1; i >= 0; i -= 1) {
  1199. labelInterval = createDuration(STOCK_SUB_DURATIONS[i]);
  1200. slotsPerLabel = wholeDivideDurations(labelInterval, slotDuration);
  1201. if (slotsPerLabel !== null && slotsPerLabel > 1) {
  1202. return labelInterval;
  1203. }
  1204. }
  1205. return slotDuration;
  1206. }
  1207. var DayTimeColsView = class extends TimeColsView {
  1208. constructor() {
  1209. super(...arguments);
  1210. this.buildTimeColsModel = memoize(buildTimeColsModel);
  1211. this.buildSlatMetas = memoize(buildSlatMetas);
  1212. }
  1213. render() {
  1214. let { options, dateEnv, dateProfileGenerator } = this.context;
  1215. let { props } = this;
  1216. let { dateProfile } = props;
  1217. let dayTableModel = this.buildTimeColsModel(dateProfile, dateProfileGenerator);
  1218. let splitProps = this.allDaySplitter.splitProps(props);
  1219. let slatMetas = this.buildSlatMetas(dateProfile.slotMinTime, dateProfile.slotMaxTime, options.slotLabelInterval, options.slotDuration, dateEnv);
  1220. let { dayMinWidth } = options;
  1221. let hasAttachedAxis = !dayMinWidth;
  1222. let hasDetachedAxis = dayMinWidth;
  1223. let headerContent = options.dayHeaders && y(DayHeader, { dates: dayTableModel.headerDates, dateProfile, datesRepDistinctDays: true, renderIntro: hasAttachedAxis ? this.renderHeadAxis : null });
  1224. let allDayContent = options.allDaySlot !== false && ((contentArg) => y(DayTable, Object.assign({}, splitProps.allDay, { dateProfile, dayTableModel, nextDayThreshold: options.nextDayThreshold, tableMinWidth: contentArg.tableMinWidth, colGroupNode: contentArg.tableColGroupNode, renderRowIntro: hasAttachedAxis ? this.renderTableRowAxis : null, showWeekNumbers: false, expandRows: false, headerAlignElRef: this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint }, this.getAllDayMaxEventProps())));
  1225. let timeGridContent = (contentArg) => y(DayTimeCols, Object.assign({}, splitProps.timed, { dayTableModel, dateProfile, axis: hasAttachedAxis, slotDuration: options.slotDuration, slatMetas, forPrint: props.forPrint, tableColGroupNode: contentArg.tableColGroupNode, tableMinWidth: contentArg.tableMinWidth, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, onSlatCoords: this.handleSlatCoords, expandRows: contentArg.expandRows, onScrollTopRequest: this.handleScrollTopRequest }));
  1226. return hasDetachedAxis ? this.renderHScrollLayout(headerContent, allDayContent, timeGridContent, dayTableModel.colCnt, dayMinWidth, slatMetas, this.state.slatCoords) : this.renderSimpleLayout(headerContent, allDayContent, timeGridContent);
  1227. }
  1228. };
  1229. function buildTimeColsModel(dateProfile, dateProfileGenerator) {
  1230. let daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
  1231. return new DayTableModel(daySeries, false);
  1232. }
  1233. var css_248z = '.fc-v-event{background-color:var(--fc-event-bg-color);border:1px solid var(--fc-event-border-color);display:block}.fc-v-event .fc-event-main{color:var(--fc-event-text-color);height:100%}.fc-v-event .fc-event-main-frame{display:flex;flex-direction:column;height:100%}.fc-v-event .fc-event-time{flex-grow:0;flex-shrink:0;max-height:100%;overflow:hidden}.fc-v-event .fc-event-title-container{flex-grow:1;flex-shrink:1;min-height:0}.fc-v-event .fc-event-title{bottom:0;max-height:100%;overflow:hidden;top:0}.fc-v-event:not(.fc-event-start){border-top-left-radius:0;border-top-right-radius:0;border-top-width:0}.fc-v-event:not(.fc-event-end){border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom-width:0}.fc-v-event.fc-event-selected:before{left:-10px;right:-10px}.fc-v-event .fc-event-resizer-start{cursor:n-resize}.fc-v-event .fc-event-resizer-end{cursor:s-resize}.fc-v-event:not(.fc-event-selected) .fc-event-resizer{height:var(--fc-event-resizer-thickness);left:0;right:0}.fc-v-event:not(.fc-event-selected) .fc-event-resizer-start{top:calc(var(--fc-event-resizer-thickness)/-2)}.fc-v-event:not(.fc-event-selected) .fc-event-resizer-end{bottom:calc(var(--fc-event-resizer-thickness)/-2)}.fc-v-event.fc-event-selected .fc-event-resizer{left:50%;margin-left:calc(var(--fc-event-resizer-dot-total-width)/-2)}.fc-v-event.fc-event-selected .fc-event-resizer-start{top:calc(var(--fc-event-resizer-dot-total-width)/-2)}.fc-v-event.fc-event-selected .fc-event-resizer-end{bottom:calc(var(--fc-event-resizer-dot-total-width)/-2)}.fc .fc-timegrid .fc-daygrid-body{z-index:2}.fc .fc-timegrid-divider{padding:0 0 2px}.fc .fc-timegrid-body{min-height:100%;position:relative;z-index:1}.fc .fc-timegrid-axis-chunk{position:relative}.fc .fc-timegrid-axis-chunk>table,.fc .fc-timegrid-slots{position:relative;z-index:1}.fc .fc-timegrid-slot{border-bottom:0;height:1.5em}.fc .fc-timegrid-slot:empty:before{content:"\\00a0"}.fc .fc-timegrid-slot-minor{border-top-style:dotted}.fc .fc-timegrid-slot-label-cushion{display:inline-block;white-space:nowrap}.fc .fc-timegrid-slot-label{vertical-align:middle}.fc .fc-timegrid-axis-cushion,.fc .fc-timegrid-slot-label-cushion{padding:0 4px}.fc .fc-timegrid-axis-frame-liquid{height:100%}.fc .fc-timegrid-axis-frame{align-items:center;display:flex;justify-content:flex-end;overflow:hidden}.fc .fc-timegrid-axis-cushion{flex-shrink:0;max-width:60px}.fc-direction-ltr .fc-timegrid-slot-label-frame{text-align:right}.fc-direction-rtl .fc-timegrid-slot-label-frame{text-align:left}.fc-liquid-hack .fc-timegrid-axis-frame-liquid{bottom:0;height:auto;left:0;position:absolute;right:0;top:0}.fc .fc-timegrid-col.fc-day-today{background-color:var(--fc-today-bg-color)}.fc .fc-timegrid-col-frame{min-height:100%;position:relative}.fc-media-screen.fc-liquid-hack .fc-timegrid-col-frame{bottom:0;height:auto;left:0;position:absolute;right:0;top:0}.fc-media-screen .fc-timegrid-cols{bottom:0;left:0;position:absolute;right:0;top:0}.fc-media-screen .fc-timegrid-cols>table{height:100%}.fc-media-screen .fc-timegrid-col-bg,.fc-media-screen .fc-timegrid-col-events,.fc-media-screen .fc-timegrid-now-indicator-container{left:0;position:absolute;right:0;top:0}.fc .fc-timegrid-col-bg{z-index:2}.fc .fc-timegrid-col-bg .fc-non-business{z-index:1}.fc .fc-timegrid-col-bg .fc-bg-event{z-index:2}.fc .fc-timegrid-col-bg .fc-highlight{z-index:3}.fc .fc-timegrid-bg-harness{left:0;position:absolute;right:0}.fc .fc-timegrid-col-events{z-index:3}.fc .fc-timegrid-now-indicator-container{bottom:0;overflow:hidden}.fc-direction-ltr .fc-timegrid-col-events{margin:0 2.5% 0 2px}.fc-direction-rtl .fc-timegrid-col-events{margin:0 2px 0 2.5%}.fc-timegrid-event-harness{position:absolute}.fc-timegrid-event-harness>.fc-timegrid-event{bottom:0;left:0;position:absolute;right:0;top:0}.fc-timegrid-event-harness-inset .fc-timegrid-event,.fc-timegrid-event.fc-event-mirror,.fc-timegrid-more-link{box-shadow:0 0 0 1px var(--fc-page-bg-color)}.fc-timegrid-event,.fc-timegrid-more-link{border-radius:3px;font-size:var(--fc-small-font-size)}.fc-timegrid-event{margin-bottom:1px}.fc-timegrid-event .fc-event-main{padding:1px 1px 0}.fc-timegrid-event .fc-event-time{font-size:var(--fc-small-font-size);margin-bottom:1px;white-space:nowrap}.fc-timegrid-event-short .fc-event-main-frame{flex-direction:row;overflow:hidden}.fc-timegrid-event-short .fc-event-time:after{content:"\\00a0-\\00a0"}.fc-timegrid-event-short .fc-event-title{font-size:var(--fc-small-font-size)}.fc-timegrid-more-link{background:var(--fc-more-link-bg-color);color:var(--fc-more-link-text-color);cursor:pointer;margin-bottom:1px;position:absolute;z-index:9999}.fc-timegrid-more-link-inner{padding:3px 2px;top:0}.fc-direction-ltr .fc-timegrid-more-link{right:0}.fc-direction-rtl .fc-timegrid-more-link{left:0}.fc .fc-timegrid-now-indicator-line{border-color:var(--fc-now-indicator-color);border-style:solid;border-width:1px 0 0;left:0;position:absolute;right:0;z-index:4}.fc .fc-timegrid-now-indicator-arrow{border-color:var(--fc-now-indicator-color);border-style:solid;margin-top:-5px;position:absolute;z-index:4}.fc-direction-ltr .fc-timegrid-now-indicator-arrow{border-bottom-color:transparent;border-top-color:transparent;border-width:5px 0 5px 6px;left:0}.fc-direction-rtl .fc-timegrid-now-indicator-arrow{border-bottom-color:transparent;border-top-color:transparent;border-width:5px 6px 5px 0;right:0}';
  1234. injectStyles(css_248z);
  1235. // node_modules/.pnpm/@fullcalendar+timegrid@6.1.14_@fullcalendar+core@6.1.14/node_modules/@fullcalendar/timegrid/index.js
  1236. var OPTION_REFINERS = {
  1237. allDaySlot: Boolean
  1238. };
  1239. var index = createPlugin({
  1240. name: "@fullcalendar/timegrid",
  1241. initialView: "timeGridWeek",
  1242. optionRefiners: OPTION_REFINERS,
  1243. views: {
  1244. timeGrid: {
  1245. component: DayTimeColsView,
  1246. usesMinMaxTime: true,
  1247. allDaySlot: true,
  1248. slotDuration: "00:30:00",
  1249. slotEventOverlap: true
  1250. // a bad name. confused with overlap/constraint system
  1251. },
  1252. timeGridDay: {
  1253. type: "timeGrid",
  1254. duration: { days: 1 }
  1255. },
  1256. timeGridWeek: {
  1257. type: "timeGrid",
  1258. duration: { weeks: 1 }
  1259. }
  1260. }
  1261. });
  1262. export {
  1263. index as default
  1264. };
  1265. //# sourceMappingURL=@fullcalendar_timegrid.js.map