@wistia/ui 3.5.1-beta.53aa0f7d.0398e32 → 3.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  /*
3
- * @license @wistia/ui v3.5.1-beta.53aa0f7d.0398e32
3
+ * @license @wistia/ui v3.5.2
4
4
  *
5
5
  * Copyright (c) 2024-2026, Wistia, Inc. and its affiliates.
6
6
  *
@@ -10,7 +10,7 @@
10
10
  import { Tooltip as Tooltip$1 } from "@base-ui/react/tooltip";
11
11
  import { Children, Fragment, cloneElement, createContext, forwardRef, isValidElement, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore, useTransition } from "react";
12
12
  import { createGlobalStyle, css, keyframes, styled } from "styled-components";
13
- import { buildTimeDuration, dateOnlyString, isArray, isBoolean, isEmptyString, isFunction, isNil, isNonEmptyArray, isNonEmptyString, isNotNil, isNotUndefined, isNumber, isRecord, isString, isUndefined, noOpFn, parseDateString } from "@wistia/utils";
13
+ import { isArray, isBoolean, isDate, isEmptyString, isFunction, isNil, isNonEmptyArray, isNonEmptyString, isNotNil, isNotUndefined, isNumber, isRecord, isString, isUndefined, noOpFn } from "@wistia/utils";
14
14
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
15
15
  import { Toaster, toast } from "sonner";
16
16
  import { getValueAndUnit } from "polished";
@@ -127,6 +127,12 @@ const globalStyleAdjustmentsCss = css`
127
127
  }
128
128
  }
129
129
 
130
+ input,
131
+ textarea,
132
+ [contenteditable] {
133
+ text-wrap: wrap;
134
+ }
135
+
130
136
  /* Remove default margin in favour of better control in authored CSS */
131
137
  body,
132
138
  h1,
@@ -365,6 +371,19 @@ const UIProvider = ({ children, id, gatedIcon = "sparkle" }) => {
365
371
  });
366
372
  };
367
373
  //#endregion
374
+ //#region src/helpers/coerceToBoolean/coerceToBoolean.ts
375
+ /**
376
+ * Converts a boolean string value `value` into a boolean. If passed
377
+ * something other than 'true' or 'false' will coerce value to boolean.
378
+ *
379
+ * @param {*} value - a value of any type
380
+ * @returns {boolean} - that value as a boolean
381
+ */
382
+ const coerceToBoolean = (value) => {
383
+ if (value === "true" || value === "false") return value === "true";
384
+ return Boolean(value);
385
+ };
386
+ //#endregion
368
387
  //#region src/helpers/copyToClipboard/copyToClipboard.ts
369
388
  /**
370
389
  * Copies a string to user's clipboard for easy pasting in another location
@@ -380,6 +399,673 @@ const copyToClipboard = async (textToCopy) => {
380
399
  });
381
400
  };
382
401
  //#endregion
402
+ //#region src/helpers/dateTime/constants.ts
403
+ const defaultLocales = ["en-US"];
404
+ const defaultTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
405
+ const milisecondsInSecond = 1e3;
406
+ const millisecondsInDay = 86400 * milisecondsInSecond;
407
+ //#endregion
408
+ //#region src/helpers/dateTime/buildTimeDuration.ts
409
+ /**
410
+ * Returns an object representing the duration in seconds, minutes and hours.
411
+ *
412
+ * @param {number} numberOfMilliseconds - number of milliseconds
413
+ * @returns {TimeDuration} -
414
+ */
415
+ const buildTimeDuration = (numberOfMilliseconds) => {
416
+ const numberOfSeconds = Math.floor(numberOfMilliseconds / milisecondsInSecond);
417
+ const numberOfMinutes = Math.floor(numberOfSeconds / 60);
418
+ const numberOfHours = Math.floor(numberOfMinutes / 60);
419
+ return {
420
+ seconds: numberOfSeconds - numberOfMinutes * 60,
421
+ minutes: numberOfMinutes - numberOfHours * 60,
422
+ hours: numberOfHours
423
+ };
424
+ };
425
+ //#endregion
426
+ //#region src/helpers/dateTime/isInvalidDate.ts
427
+ /**
428
+ * @param {*} date - a Date object - could be unknown though
429
+ * @returns {boolean} - whether it's a valid date
430
+ */
431
+ const isInvalidDate = (date) => {
432
+ if (!isDate(date)) return true;
433
+ const time = date.getTime();
434
+ return time === 0 || Number.isNaN(time);
435
+ };
436
+ //#endregion
437
+ //#region src/helpers/dateTime/dateOnlyISOString.ts
438
+ /**
439
+ * Converts a Date object into a date only string formatted to ISO8601.
440
+ *
441
+ * e.g. 2021-06-03
442
+ * @param {*} date a Date object you want to convert into a string - gracefully handles any input
443
+ * @param {object} options -
444
+ * @param {string} options.timeZone - the timezone you want date displayed in, defaults to current users time zone
445
+ * @returns {string} a formatted date string
446
+ */
447
+ const dateOnlyISOString = (date, { timeZone = defaultTimeZone } = {}) => {
448
+ if (!isDate(date) || isInvalidDate(date)) return "";
449
+ try {
450
+ const partsAsObject = new Intl.DateTimeFormat(defaultLocales, {
451
+ year: "numeric",
452
+ month: "2-digit",
453
+ day: "2-digit",
454
+ timeZone
455
+ }).formatToParts(date).reduce((map, obj) => {
456
+ map[obj.type] = obj.value;
457
+ return map;
458
+ }, {});
459
+ return `${partsAsObject.year}-${partsAsObject.month}-${partsAsObject.day}`;
460
+ } catch (error) {
461
+ console.error(error);
462
+ return "";
463
+ }
464
+ };
465
+ //#endregion
466
+ //#region src/helpers/dateTime/dateOnlyString.ts
467
+ /**
468
+ * Converts a Date object into a date only string.
469
+ *
470
+ * e.g. Jun 3, 2021 or Jun 3 if `omitYear` is true.
471
+ *
472
+ * @param {*} date a Date object you want to convert into a string - gracefully handles any input
473
+ * @param {object} options -
474
+ * @param {string} options.timeZone - the timezone you want date displayed in, defaults to current user's time zone
475
+ * @param {boolean} options.omitYear - if true, display the date without the year
476
+ * @returns {string} a formatted date string
477
+ */
478
+ const dateOnlyString = (date, { timeZone = defaultTimeZone, omitYear = false } = {}) => {
479
+ if (!isDate(date) || isInvalidDate(date)) return "";
480
+ const formatOptions = omitYear ? {
481
+ month: "short",
482
+ day: "numeric",
483
+ timeZone
484
+ } : {
485
+ dateStyle: "medium",
486
+ timeZone
487
+ };
488
+ try {
489
+ return new Intl.DateTimeFormat(defaultLocales, formatOptions).format(date);
490
+ } catch (error) {
491
+ console.error(error);
492
+ return "";
493
+ }
494
+ };
495
+ //#endregion
496
+ //#region src/helpers/dateTime/dateOnlyStringForSentence.ts
497
+ /**
498
+ * Converts a Date object into a date only string
499
+ * for use in a sentence.
500
+ *
501
+ * e.g. June 3, 2021
502
+ *
503
+ * @param {*} date - a Date object you want to convert into a string - gracefully handles any value
504
+ * @param {object} options -
505
+ * @param {string} options.timeZone - the timezone you want date displayed in, defaults to current users time zone
506
+ * @returns {string} a formatted date string
507
+ */
508
+ const dateOnlyStringForSentence = (date, { timeZone = defaultTimeZone } = {}) => {
509
+ if (!isDate(date) || isInvalidDate(date)) return "";
510
+ try {
511
+ return new Intl.DateTimeFormat(defaultLocales, {
512
+ dateStyle: "long",
513
+ timeZone
514
+ }).format(date);
515
+ } catch (error) {
516
+ console.error(error);
517
+ return "";
518
+ }
519
+ };
520
+ //#endregion
521
+ //#region src/helpers/dateTime/dateOnlyStringNumeric.ts
522
+ /**
523
+ * Converts a Date object into a date only string formatted numerically.
524
+ *
525
+ * e.g. 06/03/2021
526
+ * @param {*} date a Date object you want to convert into a string - gracefully handles any input
527
+ * @param {object} options -
528
+ * @param {string} options.timeZone - the timezone you want date displayed in, defaults to current users time zone
529
+ * @returns {string} a formatted date string
530
+ */
531
+ const dateOnlyStringNumeric = (date, { timeZone = defaultTimeZone } = {}) => {
532
+ if (!isDate(date) || isInvalidDate(date)) return "";
533
+ try {
534
+ return new Intl.DateTimeFormat(defaultLocales, {
535
+ year: "numeric",
536
+ month: "2-digit",
537
+ day: "2-digit",
538
+ timeZone
539
+ }).format(date);
540
+ } catch (error) {
541
+ console.error(error);
542
+ return "";
543
+ }
544
+ };
545
+ //#endregion
546
+ //#region src/helpers/dateTime/dateTimeToDate.ts
547
+ /**
548
+ * @param {Partial<WistiaDateTimeObject> | null} dateTime - a dateTime object
549
+ * @returns {Date | null} - the converted date or null if anything is missing
550
+ */
551
+ const dateTimeToDate = (dateTime) => {
552
+ const { year, month, dayOfMonth, hours, minutes } = dateTime ?? {};
553
+ if (year !== void 0 && month !== void 0 && dayOfMonth !== void 0) return new Date(year, month, dayOfMonth, hours ?? 0, minutes ?? 0);
554
+ return null;
555
+ };
556
+ //#endregion
557
+ //#region src/helpers/dateTime/dateTimeToISO.ts
558
+ /**
559
+ * @param {Partial<WistiaDateTimeObject>} dateTime - a dateTime object
560
+ * @returns {string | null} - string with the ISO-8601 string or null
561
+ */
562
+ const dateTimeToISO = (dateTime) => dateTimeToDate(dateTime)?.toISOString() ?? null;
563
+ //#endregion
564
+ //#region src/helpers/dateTime/dateToDateTime.ts
565
+ /**
566
+ * @typedef {Object} WistiaDateTimeObject
567
+ * @property {number} minutes - number of minutes
568
+ * @property {number} hours - number of hours
569
+ * @property {number} dayOfMonth - day of the month
570
+ * @property {number} year - year
571
+ * @property {number} month - month
572
+ */
573
+ /**
574
+ * @param {Date | null | undefined} date - a Date object
575
+ * @returns {WistiaDateTimeObject | null} - replaceMe
576
+ */
577
+ const dateToDateTime = (date) => {
578
+ if (!isDate(date)) return null;
579
+ return {
580
+ year: date.getFullYear(),
581
+ month: date.getMonth(),
582
+ dayOfMonth: date.getDate(),
583
+ hours: date.getHours(),
584
+ minutes: date.getMinutes()
585
+ };
586
+ };
587
+ //#endregion
588
+ //#region src/helpers/dateTime/dateTimeRounded.ts
589
+ /**
590
+ * @param {Date} dateTime - a dateTime object
591
+ * @param {boolean} toISOString - whether the return value should be an ISO string
592
+ * @returns {string | Date | null} - string or date depending on if toIsoString is true or false. Could be null if there's an error.
593
+ */
594
+ const dateTimeRounded = (dateTime, toISOString = true) => {
595
+ const first30Min = dateTime.getMinutes() <= 30;
596
+ const hours = first30Min ? dateTime.getHours() : dateTime.getHours() + 1;
597
+ const minutes = first30Min ? 30 : 0;
598
+ const dateWithTime = {
599
+ ...dateToDateTime(dateTime),
600
+ hours,
601
+ minutes
602
+ };
603
+ if (toISOString) return dateTimeToISO(dateWithTime);
604
+ return dateTimeToDate(dateWithTime);
605
+ };
606
+ //#endregion
607
+ //#region src/helpers/dateTime/dateTimeString.ts
608
+ /**
609
+ * Converts a Date object into a date and time string.
610
+ *
611
+ * e.g. Jun 3, 2021, 11:52 AM
612
+ *
613
+ * NOTE: you should probably use timeAgoString when trying to display
614
+ * an updated/created timestamp.
615
+ *
616
+ * @param {*} date - a Date object you want to convert into a string - gracefully handles any value
617
+ * @param {object} options -
618
+ * @param {string} options.timeZone - the timezone you want date displayed in, defaults to current users time zone
619
+ * @returns {string} a formatted date string
620
+ */
621
+ const dateTimeString = (date, { timeZone = defaultTimeZone, omitYear = false } = {}) => {
622
+ if (isNil(date)) return "";
623
+ const formattedDate = new Date(date);
624
+ if (isInvalidDate(formattedDate)) return "";
625
+ try {
626
+ const baseOptions = {
627
+ month: "short",
628
+ day: "numeric",
629
+ hour: "numeric",
630
+ minute: "2-digit",
631
+ timeZone
632
+ };
633
+ const options = omitYear ? baseOptions : {
634
+ ...baseOptions,
635
+ year: "numeric"
636
+ };
637
+ return formattedDate.toLocaleDateString(defaultLocales, options);
638
+ } catch (error) {
639
+ console.error(error);
640
+ return "";
641
+ }
642
+ };
643
+ //#endregion
644
+ //#region src/helpers/dateTime/dateTimeStringForSentence.ts
645
+ /**
646
+ * Converts a Date object into a date and time string
647
+ * for use in a sentence.
648
+ *
649
+ * e.g. June 3, 2021, 11:52 AM
650
+ *
651
+ * NOTE: you should probably use timeAgoString when trying to display
652
+ * an updated/created timestamp.
653
+ *
654
+ * @param {*} date - a Date object you want to convert into a string - gracefully handles any value
655
+ * @param {object} options -
656
+ * @param {string} options.timeZone - the timezone you want date displayed in, defaults to current users time zone
657
+ * @returns {string} a formatted date string
658
+ */
659
+ const dateTimeStringForSentence = (date, { timeZone = defaultTimeZone } = {}) => {
660
+ if (!isDate(date) || isInvalidDate(date)) return "";
661
+ try {
662
+ const { year, month, day, hour, minute, dayPeriod } = new Intl.DateTimeFormat(defaultLocales, {
663
+ month: "long",
664
+ day: "numeric",
665
+ year: "numeric",
666
+ hour: "numeric",
667
+ minute: "2-digit",
668
+ timeZone
669
+ }).formatToParts(date).reduce((acc, part) => {
670
+ if (part.type !== "literal") acc[part.type] = part.value;
671
+ return acc;
672
+ }, {});
673
+ return `${month} ${day}, ${year}, ${hour}:${minute} ${dayPeriod}`;
674
+ } catch (error) {
675
+ console.error(error);
676
+ return "";
677
+ }
678
+ };
679
+ //#endregion
680
+ //#region src/helpers/dateTime/dateUTCOffset.ts
681
+ /**
682
+ * Given a date, shows the UTC offset.
683
+ * @param {Date} date a Date object for calculating offset.
684
+ * @returns {string} - string representing the UTC offset
685
+ */
686
+ const dateUTCOffset = (date) => {
687
+ const offsetInHours = date.getTimezoneOffset() / 60 * -1;
688
+ const hours = Math.round(offsetInHours);
689
+ const minutes = (offsetInHours - hours) * 60;
690
+ return `${hours >= 0 ? "+" : ""}${`${hours}`.padStart(2, "0")}:${`${minutes}`.padStart(2, "0")}`;
691
+ };
692
+ //#endregion
693
+ //#region src/helpers/dateTime/dayOfWeekString.ts
694
+ /**
695
+ * Converts a Date object into a month and day string formatted numerically.
696
+ *
697
+ * e.g. Thursday
698
+ * @param {Date} date a Date object you want to convert into a string
699
+ * @param {object} options -
700
+ * @param {string} options.timeZone - the timezone you want date displayed in, defaults to current users time zone
701
+ * @returns {string} a formatted date string
702
+ */
703
+ const dayOfWeekString = (date, { timeZone = defaultTimeZone } = {}) => {
704
+ if (date === null) return "";
705
+ try {
706
+ return new Intl.DateTimeFormat(defaultLocales, {
707
+ weekday: "long",
708
+ timeZone
709
+ }).format(date);
710
+ } catch (error) {
711
+ console.error(error);
712
+ return "";
713
+ }
714
+ };
715
+ //#endregion
716
+ //#region src/helpers/dateTime/padTimeInteger.ts
717
+ /**
718
+ * @param {number} num - pads integer with leading zero
719
+ * @returns {string} - integer with padding as string
720
+ */
721
+ const padTimeInteger = (num) => num.toString().padStart(2, "0");
722
+ //#endregion
723
+ //#region src/helpers/dateTime/mediaDurationString.ts
724
+ /**
725
+ * A string representation of a duration for a media. Assumes most medias
726
+ * are under an hour so only shows hours if media is over hour.
727
+ *
728
+ * @param {number} numberOfMilliseconds - number of milliseconds
729
+ * @returns {string} - a string representation for duration
730
+ */
731
+ const mediaDurationString = (numberOfMilliseconds) => {
732
+ const { hours, minutes, seconds } = buildTimeDuration(numberOfMilliseconds);
733
+ if (hours < 1) return `${minutes}:${padTimeInteger(seconds)}`;
734
+ return `${hours}:${padTimeInteger(minutes)}:${padTimeInteger(seconds)}`;
735
+ };
736
+ //#endregion
737
+ //#region src/helpers/dateTime/millisecondsToDurationISOString.ts
738
+ /**
739
+ * Given number of miliseconds, returns the iso8601 string rounded down from
740
+ * number of seconds. Mainly copied from https://github.com/wistia/player-modern/blob/master/src/utilities/iso8601Helper.js#L54
741
+ * but modified to support milliseconds
742
+ *
743
+ * @param {number} numberOfMilliseconds - number of milliseconds
744
+ * @returns {string} an iso8601 string format of duration
745
+ */
746
+ const millisecondsToDurationISOString = (numberOfMilliseconds) => {
747
+ const { seconds, minutes, hours } = buildTimeDuration(numberOfMilliseconds);
748
+ let string = "PT";
749
+ if (hours) string += `${hours}H`;
750
+ if (minutes) string += `${minutes}M`;
751
+ if (seconds) string += `${seconds}S`;
752
+ if (!(seconds || minutes || hours)) string += "0S";
753
+ return string;
754
+ };
755
+ //#endregion
756
+ //#region src/helpers/dateTime/monthDayStringNumeric.ts
757
+ /**
758
+ * Converts a Date object into a month and day string formatted numerically.
759
+ *
760
+ * e.g. 06/03/2021
761
+ * @param {*} date a Date object you want to convert into a string - gracefully handles any value
762
+ * @param {object} options -
763
+ * @param {string} options.timeZone - the timezone you want date displayed in, defaults to current users time zone
764
+ * @returns {string} a formatted date string
765
+ */
766
+ const monthDayStringNumeric = (date, { timeZone = defaultTimeZone } = {}) => {
767
+ if (!isDate(date) || isInvalidDate(date)) return "";
768
+ try {
769
+ return new Intl.DateTimeFormat(defaultLocales, {
770
+ month: "2-digit",
771
+ day: "2-digit",
772
+ timeZone
773
+ }).format(date);
774
+ } catch (error) {
775
+ console.error(error);
776
+ return "";
777
+ }
778
+ };
779
+ //#endregion
780
+ //#region src/helpers/dateTime/parseDateString.ts
781
+ const MONTH_NAMES = [
782
+ "January",
783
+ "February",
784
+ "March",
785
+ "April",
786
+ "May",
787
+ "June",
788
+ "July",
789
+ "August",
790
+ "September",
791
+ "October",
792
+ "November",
793
+ "December"
794
+ ];
795
+ const MONTH_ABBREVIATIONS = MONTH_NAMES.map((name) => name.slice(0, 3));
796
+ const startOfDay = (date) => {
797
+ const result = new Date(date);
798
+ result.setHours(0, 0, 0, 0);
799
+ return result;
800
+ };
801
+ const startOfToday = () => startOfDay(/* @__PURE__ */ new Date());
802
+ const startOfTomorrow = () => {
803
+ const tomorrow = startOfToday();
804
+ tomorrow.setDate(tomorrow.getDate() + 1);
805
+ return tomorrow;
806
+ };
807
+ const monthIndexIn = (names, value) => names.findIndex((name) => name.toLowerCase() === value.toLowerCase());
808
+ const toNumberOrUndefined = (value) => value === void 0 ? void 0 : Number(value);
809
+ const DATE_PATTERNS = [
810
+ {
811
+ regex: new RegExp(`^(${MONTH_ABBREVIATIONS.join("|")}) (\\d{1,2})(?:, (\\d{1,4}))?$`, "i"),
812
+ toParts: ([, month, day, year]) => ({
813
+ monthIndex: monthIndexIn(MONTH_ABBREVIATIONS, month ?? ""),
814
+ day: Number(day),
815
+ year: toNumberOrUndefined(year)
816
+ })
817
+ },
818
+ {
819
+ regex: new RegExp(`^(${MONTH_NAMES.join("|")}) (\\d{1,2})(?:, (\\d{1,4}))?$`, "i"),
820
+ toParts: ([, month, day, year]) => ({
821
+ monthIndex: monthIndexIn(MONTH_NAMES, month ?? ""),
822
+ day: Number(day),
823
+ year: toNumberOrUndefined(year)
824
+ })
825
+ },
826
+ {
827
+ regex: /^(\d{1,2})\/(\d{1,2})(?:\/(\d{1,4}))?$/,
828
+ toParts: ([, month, day, year]) => ({
829
+ monthIndex: Number(month) - 1,
830
+ day: Number(day),
831
+ year: toNumberOrUndefined(year)
832
+ })
833
+ },
834
+ {
835
+ regex: /^(\d{1,2})-(\d{1,2})(?:-(\d{1,4}))?$/,
836
+ toParts: ([, month, day, year]) => ({
837
+ monthIndex: Number(month) - 1,
838
+ day: Number(day),
839
+ year: toNumberOrUndefined(year)
840
+ })
841
+ },
842
+ {
843
+ regex: /^(\d{1,4})-(\d{1,2})-(\d{1,2})$/,
844
+ toParts: ([, year, month, day]) => ({
845
+ monthIndex: Number(month) - 1,
846
+ day: Number(day),
847
+ year: Number(year)
848
+ })
849
+ }
850
+ ];
851
+ const toValidDate = ({ monthIndex, day, year }, referenceDate) => {
852
+ if (year === 0) return null;
853
+ const resolvedYear = year ?? referenceDate.getFullYear();
854
+ const date = new Date(referenceDate.getFullYear(), 0, 1);
855
+ date.setFullYear(resolvedYear, monthIndex, day);
856
+ return date.getFullYear() === resolvedYear && date.getMonth() === monthIndex && date.getDate() === day ? date : null;
857
+ };
858
+ const parseDateString = (str) => {
859
+ const trimmed = str.trim();
860
+ if (!trimmed) return null;
861
+ const lower = trimmed.toLowerCase();
862
+ if (lower === "today") return startOfToday();
863
+ if (lower === "tomorrow") return startOfTomorrow();
864
+ const monthIndex = MONTH_NAMES.findIndex((name) => name.toLowerCase().startsWith(lower));
865
+ if (monthIndex !== -1) {
866
+ const today = startOfToday();
867
+ let date = new Date(today.getFullYear(), monthIndex, 1);
868
+ if (date.getTime() < Date.now()) date = new Date(today.getFullYear() + 1, monthIndex, 1);
869
+ return date;
870
+ }
871
+ const referenceDate = /* @__PURE__ */ new Date();
872
+ for (const { regex, toParts } of DATE_PATTERNS) {
873
+ const match = trimmed.match(regex);
874
+ if (match) {
875
+ const parsed = toValidDate(toParts(match), referenceDate);
876
+ if (parsed !== null) return parsed;
877
+ }
878
+ }
879
+ const native = new Date(trimmed);
880
+ if (!Number.isNaN(native.getTime())) return startOfDay(native);
881
+ return null;
882
+ };
883
+ //#endregion
884
+ //#region src/helpers/dateTime/sessionDurationString.ts
885
+ /**
886
+ * A string representation of a duration for a user session. Assumes that
887
+ * sessions may or may not be more than an hour. To prevent confusion all
888
+ * times show hours, even those that are less than an hour.
889
+ *
890
+ * @param {number} numberOfMilliseconds - number of milliseconds
891
+ * @returns {string} - a string representation of duration
892
+ */
893
+ const sessionDurationString = (numberOfMilliseconds) => {
894
+ const { hours, minutes, seconds } = buildTimeDuration(numberOfMilliseconds);
895
+ return `${hours}:${padTimeInteger(minutes)}:${padTimeInteger(seconds)}`;
896
+ };
897
+ //#endregion
898
+ //#region src/helpers/dateTime/getLocalDateParts.ts
899
+ /**
900
+ * Get local year, month, day parts from a Date using Intl.DateTimeFormat.
901
+ * This ignores the time of day (hours, minutes, etc.).
902
+ *
903
+ * @param {Date} date
904
+ * @returns {{ year: number, month: number, day: number }}
905
+ */
906
+ const getLocalDateParts = (date) => {
907
+ const parts = new Intl.DateTimeFormat(defaultLocales, {
908
+ year: "numeric",
909
+ month: "numeric",
910
+ day: "numeric",
911
+ timeZone: defaultTimeZone
912
+ }).formatToParts(date);
913
+ const yearPart = parts.find((part) => part.type === "year");
914
+ const monthPart = parts.find((part) => part.type === "month");
915
+ const dayPart = parts.find((part) => part.type === "day");
916
+ if (isNil(yearPart) || isNil(monthPart) || isNil(dayPart)) throw new Error("Failed to parse date parts");
917
+ return {
918
+ year: Math.trunc(Number(yearPart.value)),
919
+ month: Math.trunc(Number(monthPart.value)),
920
+ day: Math.trunc(Number(dayPart.value))
921
+ };
922
+ };
923
+ //#endregion
924
+ //#region src/helpers/dateTime/differenceInCalendarDays.ts
925
+ /**
926
+ * Returns the difference in calendar days between two dates in local time,
927
+ * ignoring the time of day.
928
+ *
929
+ * @param {Date|number} dateLeft - The later date (or timestamp).
930
+ * @param {Date|number} dateRight - The earlier date (or timestamp).
931
+ * @returns {number} - Number of calendar days (can be negative).
932
+ */
933
+ const differenceInCalendarDays = (dateLeft, dateRight) => {
934
+ const leftDate = isDate(dateLeft) ? dateLeft : new Date(dateLeft);
935
+ const rightDate = isDate(dateRight) ? dateRight : new Date(dateRight);
936
+ if (Number.isNaN(leftDate.getTime()) || Number.isNaN(rightDate.getTime())) return NaN;
937
+ const { year: y1, month: m1, day: d1 } = getLocalDateParts(leftDate);
938
+ const { year: y2, month: m2, day: d2 } = getLocalDateParts(rightDate);
939
+ const msDiff = new Date(y1, m1 - 1, d1).getTime() - new Date(y2, m2 - 1, d2).getTime();
940
+ return Math.round(msDiff / millisecondsInDay);
941
+ };
942
+ //#endregion
943
+ //#region src/helpers/dateTime/timeAgoString.ts
944
+ /**
945
+ * Shows time ago relative to current time.
946
+ *
947
+ * examples:
948
+ *
949
+ * < 1 minute ago
950
+ *
951
+ * 33 minutes ago
952
+ *
953
+ * Today, 3:30 PM
954
+ *
955
+ * Yesterday, 6:22 AM
956
+ *
957
+ * Nov 11, 11:32 AM
958
+ *
959
+ * Feb 23, 2020, 1:55 PM
960
+ *
961
+ * or when `includeTime` is false:
962
+ *
963
+ * Today
964
+ *
965
+ * Yesterday
966
+ *
967
+ * on Thursday
968
+ *
969
+ * Nov 11
970
+ *
971
+ * Feb 23, 2020
972
+ *
973
+ * NOTE: timeAgoString doesn't support multiple time zones since doing so would
974
+ * complicate calculations for whether to use "Today" or "Yesterday".
975
+ * @param {Date} date - the date relative to now
976
+ * @param {object} options -
977
+ * @param {Date} options.nowAnchor - The date used to calculate relative to now. Defaults to current date but can be overwritten for tests.
978
+ * @param {boolean} options.includeTime - Whether to include the time in the output. Defaults to true.
979
+ * @returns {string} - a string representation of the date.
980
+ */
981
+ const timeAgoString = (date, { nowAnchor = /* @__PURE__ */ new Date(), includeTime = true } = {}) => {
982
+ if (isInvalidDate(date)) return "";
983
+ const minutesAgo = (nowAnchor.valueOf() - date.valueOf()) / (60 * milisecondsInSecond);
984
+ const minutesAgoRounded = Math.round(minutesAgo);
985
+ const differenceInDays = differenceInCalendarDays(nowAnchor, date);
986
+ const isSameYear = date.getFullYear() === nowAnchor.getFullYear();
987
+ if (minutesAgo < 0) return dateTimeString(date);
988
+ if (minutesAgo < 1) return "< 1 minute ago";
989
+ if (minutesAgoRounded < 2) return "1 minute ago";
990
+ if (minutesAgoRounded <= 60) return `${minutesAgoRounded} minutes ago`;
991
+ if (differenceInDays === 0) return includeTime ? `Today, ${Intl.DateTimeFormat(defaultLocales, {
992
+ hour: "numeric",
993
+ minute: "2-digit"
994
+ }).format(date)}` : "Today";
995
+ if (differenceInDays === 1) return includeTime ? `Yesterday, ${Intl.DateTimeFormat(defaultLocales, {
996
+ hour: "numeric",
997
+ minute: "2-digit"
998
+ }).format(date)}` : "Yesterday";
999
+ if (differenceInDays < 7 && !includeTime) return `on ${dayOfWeekString(date)}`;
1000
+ return includeTime ? dateTimeString(date, { omitYear: isSameYear }) : dateOnlyString(date, { omitYear: false });
1001
+ };
1002
+ //#endregion
1003
+ //#region src/helpers/dateTime/timeOnlyString.ts
1004
+ /**
1005
+ * Converts a Date object into a time only string.
1006
+ *
1007
+ * e.g. 7:30 AM
1008
+ * @param {*} date a Date object you want to convert into a string - gracefully handles any value
1009
+ * @param {object} options -
1010
+ * @param {string} options.timeZone - the timezone you want date displayed in, defaults to current users time zone
1011
+ * @returns {string} a formatted date string
1012
+ */
1013
+ const timeOnlyString = (date, { timeZone = defaultTimeZone } = {}) => {
1014
+ if (!isDate(date) || isInvalidDate(date)) return "";
1015
+ try {
1016
+ return new Intl.DateTimeFormat(defaultLocales, {
1017
+ timeStyle: "short",
1018
+ timeZone
1019
+ }).format(date);
1020
+ } catch (error) {
1021
+ console.error(error);
1022
+ return "";
1023
+ }
1024
+ };
1025
+ //#endregion
1026
+ //#region src/helpers/dateTime/index.ts
1027
+ const dateTime = {
1028
+ buildTimeDuration,
1029
+ dateOnlyISOString,
1030
+ dateOnlyString,
1031
+ dateOnlyStringForSentence,
1032
+ dateOnlyStringNumeric,
1033
+ dateTimeRounded,
1034
+ dateTimeString,
1035
+ dateTimeStringForSentence,
1036
+ dateTimeToDate,
1037
+ dateTimeToISO,
1038
+ dateToDateTime,
1039
+ dateUTCOffset,
1040
+ dayOfWeekString,
1041
+ mediaDurationString,
1042
+ millisecondsToDurationISOString,
1043
+ monthDayStringNumeric,
1044
+ parseDateString,
1045
+ sessionDurationString,
1046
+ timeAgoString,
1047
+ timeOnlyString
1048
+ };
1049
+ //#endregion
1050
+ //#region src/helpers/isUrl/isUrl.ts
1051
+ /**
1052
+ * Loosely validates a URL string
1053
+ *
1054
+ * @param {*} str - a string to validate - could be an unknown type
1055
+ * @return {boolean} - whether string appears to be a url
1056
+ */
1057
+ const isUrl = (str) => {
1058
+ const protocolAndDomain = /^(?:\w+:)?\/\/(\S+)$/;
1059
+ const localhostDomain = /^localhost[:?\d]*(?:[^:?\d]\S*)?$/;
1060
+ const nonLocalhostDomain = /^[^\s.]+\.\S{2,}$/;
1061
+ if (!isString(str)) return false;
1062
+ const match = protocolAndDomain.exec(str);
1063
+ if (!match) return false;
1064
+ const remaining = match[1];
1065
+ if (remaining === void 0 || !remaining) return false;
1066
+ return localhostDomain.test(remaining) || nonLocalhostDomain.test(remaining);
1067
+ };
1068
+ //#endregion
383
1069
  //#region src/helpers/getBackgroundGradient/getBackgroundGradient.ts
384
1070
  const gradients = {
385
1071
  defaultDarkOne: css`
@@ -581,6 +1267,15 @@ const mq = {
581
1267
  xlAndDown
582
1268
  };
583
1269
  //#endregion
1270
+ //#region src/helpers/stripExtension/stripExtension.ts
1271
+ /**
1272
+ * Removes file extension from string
1273
+ *
1274
+ * @param {string} str - string to have file extension removed from
1275
+ * @returns {string} - string with file extension removed
1276
+ */
1277
+ const stripExtension = (str) => (str || "").replace(/\.[^/.]{1,4}$/, "");
1278
+ //#endregion
584
1279
  //#region src/hooks/useAriaLive/useAriaLive.tsx
585
1280
  const useAriaLive = () => {
586
1281
  const context = useContext(AriaLiveContext);
@@ -13914,7 +14609,9 @@ const InputClickToCopy = ({ value, onCopy, disabled = false, ref, ...props }) =>
13914
14609
  };
13915
14610
  //#endregion
13916
14611
  //#region src/components/InputDuration/constants.ts
13917
- const MILLISECONDS_PER_SECOND = 1e3;
14612
+ const SECONDS_PER_MINUTE = 60;
14613
+ const MAX_MINUTES_UNIT_VALUE = 59;
14614
+ const SECONDS_PER_TEN_MINUTES = 600;
13918
14615
  const SECONDS_PER_HOUR = 3600;
13919
14616
  const ONE_HUNDREDTH_OF_A_SECOND = .01;
13920
14617
  const MAX_TIME = 35999.99;
@@ -13952,13 +14649,13 @@ const getSecondsFormatter = (decimalUnitLength) => {
13952
14649
  });
13953
14650
  };
13954
14651
  const isValidHour = (number) => Number.isInteger(number) && number >= 0;
13955
- const isValidMinute = (number) => Number.isInteger(number) && number >= 0 && number <= 59;
13956
- const isValidSecond = (number) => Number.isFinite(number) && number >= 0 && number < 60;
14652
+ const isValidMinute = (number) => Number.isInteger(number) && number >= 0 && number <= MAX_MINUTES_UNIT_VALUE;
14653
+ const isValidSecond = (number) => Number.isFinite(number) && number >= 0 && number < SECONDS_PER_MINUTE;
13957
14654
  const durationValueToSeconds = (formattedTimeString) => {
13958
14655
  const segments = formattedTimeString.split(":");
13959
14656
  if (segments.length <= 3) {
13960
14657
  const [seconds = 0, minutes = 0, hours = 0] = segments.toReversed().map(Number);
13961
- if (isValidSecond(seconds) && isValidMinute(minutes) && isValidHour(hours)) return hours * SECONDS_PER_HOUR + minutes * 60 + seconds;
14658
+ if (isValidSecond(seconds) && isValidMinute(minutes) && isValidHour(hours)) return hours * SECONDS_PER_HOUR + minutes * SECONDS_PER_MINUTE + seconds;
13962
14659
  }
13963
14660
  throw new SyntaxError(`Invalid time (${formattedTimeString})`);
13964
14661
  };
@@ -13977,7 +14674,7 @@ const getFormattedSeconds = ({ seconds, decimalUnitLength }) => {
13977
14674
  const convertSecondsToHMSUnits = (durationInSeconds) => {
13978
14675
  const wholeSeconds = Math.trunc(durationInSeconds);
13979
14676
  const fractionalSeconds = durationInSeconds - wholeSeconds;
13980
- const { hours, minutes, seconds } = buildTimeDuration(wholeSeconds * MILLISECONDS_PER_SECOND);
14677
+ const { hours, minutes, seconds } = buildTimeDuration(wholeSeconds * milisecondsInSecond);
13981
14678
  return {
13982
14679
  hours,
13983
14680
  minutes,
@@ -14002,9 +14699,9 @@ const secondsToDurationValue = ({ seconds: durationInSeconds, maxUnit, decimalUn
14002
14699
  ].filter(Boolean).join(":");
14003
14700
  };
14004
14701
  const getMaxUnit = (seconds) => {
14005
- if (seconds >= 3600) return "hours";
14006
- if (seconds >= 600) return "tens-of-minutes";
14007
- if (seconds >= 60) return "minutes";
14702
+ if (seconds >= SECONDS_PER_HOUR) return "hours";
14703
+ if (seconds >= SECONDS_PER_TEN_MINUTES) return "tens-of-minutes";
14704
+ if (seconds >= SECONDS_PER_MINUTE) return "minutes";
14008
14705
  return "seconds";
14009
14706
  };
14010
14707
  const clampSeconds = ({ maxSeconds, minSeconds, seconds }) => {
@@ -14316,7 +15013,7 @@ const useInputDuration = ({ decimalUnitLength, maxSeconds, minSeconds, onChangeV
14316
15013
  return;
14317
15014
  }
14318
15015
  if (selectedUnit === "minutes" || selectedUnit === "tens-of-minutes") {
14319
- incrementBySeconds(60);
15016
+ incrementBySeconds(SECONDS_PER_MINUTE);
14320
15017
  return;
14321
15018
  }
14322
15019
  if (selectedUnit === "seconds") {
@@ -14336,7 +15033,7 @@ const useInputDuration = ({ decimalUnitLength, maxSeconds, minSeconds, onChangeV
14336
15033
  return;
14337
15034
  }
14338
15035
  if (selectedUnit === "minutes" || selectedUnit === "tens-of-minutes") {
14339
- decrementBySeconds(60);
15036
+ decrementBySeconds(SECONDS_PER_MINUTE);
14340
15037
  return;
14341
15038
  }
14342
15039
  if (selectedUnit === "seconds") {
@@ -14423,7 +15120,7 @@ const useInputDuration = ({ decimalUnitLength, maxSeconds, minSeconds, onChangeV
14423
15120
  selectUnitToRight();
14424
15121
  return;
14425
15122
  }
14426
- if (selectedUnit === "tens-of-minutes" && number >= 6 && !secondDigitMightBeTypedNext.current) {
15123
+ if (selectedUnit === "tens-of-minutes" && number >= SECONDS_PER_MINUTE / 10 && !secondDigitMightBeTypedNext.current) {
14427
15124
  maybeSetInputValueAndTriggerOnChange(`${textToLeftOfSelection}0${number.toString()}${textToRightOfSelection}`);
14428
15125
  secondDigitMightBeTypedNext.current = false;
14429
15126
  selectUnitToRight();
@@ -14445,7 +15142,7 @@ const useInputDuration = ({ decimalUnitLength, maxSeconds, minSeconds, onChangeV
14445
15142
  selectUnitToRight();
14446
15143
  return;
14447
15144
  }
14448
- if (selectedUnit === "seconds" && number >= 6 && !secondDigitMightBeTypedNext.current) {
15145
+ if (selectedUnit === "seconds" && number >= SECONDS_PER_MINUTE / 10 && !secondDigitMightBeTypedNext.current) {
14449
15146
  maybeSetInputValueAndTriggerOnChange(`${textToLeftOfSelection}0${number.toString()}${textToRightOfSelection}`);
14450
15147
  secondDigitMightBeTypedNext.current = false;
14451
15148
  selectUnitToRight();
@@ -17484,6 +18181,6 @@ const WistiaLogo = ({ description, height = 100, hoverColor, href, iconOnly = fa
17484
18181
  };
17485
18182
  WistiaLogo.displayName = "WistiaLogo_UI";
17486
18183
  //#endregion
17487
- export { ActionButton, Avatar, Badge, Banner, Box, Breadcrumb, Breadcrumbs, Button, ButtonGroup, Card, Center, Checkbox, CheckboxCard, CheckboxGroup, CheckboxMenuItem, ClickRegion, Collapsible, CollapsibleContent, CollapsibleTrigger, CollapsibleTriggerIcon, ColorGrid, ColorGridOption, ColorList, ColorListGroup, ColorListOption, ColorPicker, ColorPickerPopoverContent, ColorPickerSection, ColorPickerTrigger, ColorSchemeWrapper, Combobox, ComboboxOption, ContextMenu, ContrastControls, ContrastEnforcerSwitch, ContrastIndicator, ContrastPreview, CustomizableThemeWrapper, DOCUMENT_COLOR_MODE_ATTRIBUTE, DataCard, DataCardHoverArrow, DataCardTrend, DataCards, DataList, DataListItem, DataListItemLabel, DataListItemValue, DatePicker, Dimmer, Divider, EditableHeading, EditableText, EditableTextCancelButton, EditableTextContext, EditableTextDisplay, EditableTextInput, EditableTextLabel, EditableTextRoot, EditableTextSubmitButton, EditableTextTrigger, Ellipsis, FeatureCard, FeatureCardImage, FileAmountLimitValidator, FileSizeValidator, FileTypeValidator, FilterMenu, FilterMenuItem, Form, FormErrorSummary, FormField, FormGroup, Grid, Heading, HexColorInput, HueSlider, Icon, IconButton, IconChip, Image, ImageDimensionsValidator, Input, InputClickToCopy, InputDuration, InputPassword, KeyboardShortcut, Label, Link, List, ListItem, Mark, Markdown, Menu, MenuItem, MenuItemDescription, MenuItemLabel, MenuLabel, MenuRadioGroup, Meter, Modal, ModalCallout, ModalCallouts, PersistentFileAmountLimitValidator, Popover, PopoverAnchor, PopoverArrow, PopoverClose, PopoverCloseButton, PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger, PreviewCard, ProgressBar, Radio, RadioCard, RadioCardImage, RadioGroup, RadioMenuItem, SaturationAndValuePicker, ScreenReaderOnly, ScrollArea, SegmentedControl, SegmentedControlItem, Select, SelectOption, SelectOptionGroup, Sidebar, SidebarButton, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarSearchInput, SidebarTitle, Slider, SplitButton, Stack, SubMenu, Switch, Table, TableBody, TableCell, TableFoot, TableHead, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, Text, Thumbnail, ThumbnailBadge, ThumbnailCollage, TileButton, Tooltip, UIProvider, ValueNameOrHexCode, ValueSwatch, WistiaLogo, calculateContrast, colorModeOptions, colorSchemeOptions, copyToClipboard, documentColorModeOptions, getBackgroundGradient, getDocumentColorMode, getSemiRandomBackgroundGradient, iconSizeMap, isKeyboardKey, mergeRefs, mq, setDocumentColorMode, useActiveMq, useAriaLive, useBoolean, useClipboard, useDocumentColorMode, useElementObserver, useFilePicker, useFocusTrap, useForceUpdate, useFormState, useImperativeFilePicker, useIsHovered, useKey, useKeyPress, useLocalStorage, useLockBodyScroll, useMq, useOnClickOutside, usePreviousValue, useToast, useWindowSize, validateWithYup };
18184
+ export { ActionButton, Avatar, Badge, Banner, Box, Breadcrumb, Breadcrumbs, Button, ButtonGroup, Card, Center, Checkbox, CheckboxCard, CheckboxGroup, CheckboxMenuItem, ClickRegion, Collapsible, CollapsibleContent, CollapsibleTrigger, CollapsibleTriggerIcon, ColorGrid, ColorGridOption, ColorList, ColorListGroup, ColorListOption, ColorPicker, ColorPickerPopoverContent, ColorPickerSection, ColorPickerTrigger, ColorSchemeWrapper, Combobox, ComboboxOption, ContextMenu, ContrastControls, ContrastEnforcerSwitch, ContrastIndicator, ContrastPreview, CustomizableThemeWrapper, DOCUMENT_COLOR_MODE_ATTRIBUTE, DataCard, DataCardHoverArrow, DataCardTrend, DataCards, DataList, DataListItem, DataListItemLabel, DataListItemValue, DatePicker, Dimmer, Divider, EditableHeading, EditableText, EditableTextCancelButton, EditableTextContext, EditableTextDisplay, EditableTextInput, EditableTextLabel, EditableTextRoot, EditableTextSubmitButton, EditableTextTrigger, Ellipsis, FeatureCard, FeatureCardImage, FileAmountLimitValidator, FileSizeValidator, FileTypeValidator, FilterMenu, FilterMenuItem, Form, FormErrorSummary, FormField, FormGroup, Grid, Heading, HexColorInput, HueSlider, Icon, IconButton, IconChip, Image, ImageDimensionsValidator, Input, InputClickToCopy, InputDuration, InputPassword, KeyboardShortcut, Label, Link, List, ListItem, Mark, Markdown, Menu, MenuItem, MenuItemDescription, MenuItemLabel, MenuLabel, MenuRadioGroup, Meter, Modal, ModalCallout, ModalCallouts, PersistentFileAmountLimitValidator, Popover, PopoverAnchor, PopoverArrow, PopoverClose, PopoverCloseButton, PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger, PreviewCard, ProgressBar, Radio, RadioCard, RadioCardImage, RadioGroup, RadioMenuItem, SaturationAndValuePicker, ScreenReaderOnly, ScrollArea, SegmentedControl, SegmentedControlItem, Select, SelectOption, SelectOptionGroup, Sidebar, SidebarButton, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarSearchInput, SidebarTitle, Slider, SplitButton, Stack, SubMenu, Switch, Table, TableBody, TableCell, TableFoot, TableHead, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, Text, Thumbnail, ThumbnailBadge, ThumbnailCollage, TileButton, Tooltip, UIProvider, ValueNameOrHexCode, ValueSwatch, WistiaLogo, buildTimeDuration, calculateContrast, coerceToBoolean, colorModeOptions, colorSchemeOptions, copyToClipboard, dateOnlyISOString, dateOnlyString, dateOnlyStringForSentence, dateOnlyStringNumeric, dateTime, dateTimeRounded, dateTimeString, dateTimeStringForSentence, dateTimeToDate, dateTimeToISO, dateToDateTime, dateUTCOffset, dayOfWeekString, documentColorModeOptions, getBackgroundGradient, getDocumentColorMode, getSemiRandomBackgroundGradient, iconSizeMap, isKeyboardKey, isUrl, mediaDurationString, mergeRefs, millisecondsToDurationISOString, monthDayStringNumeric, mq, parseDateString, sessionDurationString, setDocumentColorMode, stripExtension, timeAgoString, timeOnlyString, useActiveMq, useAriaLive, useBoolean, useClipboard, useDocumentColorMode, useElementObserver, useFilePicker, useFocusTrap, useForceUpdate, useFormState, useImperativeFilePicker, useIsHovered, useKey, useKeyPress, useLocalStorage, useLockBodyScroll, useMq, useOnClickOutside, usePreviousValue, useToast, useWindowSize, validateWithYup };
17488
18185
 
17489
18186
  //# sourceMappingURL=index.js.map