@wistia/ui 1.4.0 → 1.4.1-beta.11a672bb.eaf1b95
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.d.ts +45 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +123 -25
- package/dist/index.js.map +1 -1
- package/package.json +7 -9
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
/*
|
|
3
|
-
* @license @wistia/ui v1.4.
|
|
3
|
+
* @license @wistia/ui v1.4.1-beta.11a672bb.eaf1b95
|
|
4
4
|
*
|
|
5
5
|
* Copyright (c) 2024-2026, Wistia, Inc. and its affiliates.
|
|
6
6
|
*
|
|
@@ -13,12 +13,6 @@ import { createGlobalStyle, css, keyframes, styled } from "styled-components";
|
|
|
13
13
|
import { isArray, isBoolean, isDate, isEmptyString, isFunction, isNil, isNonEmptyArray, isNonEmptyString, isNotNil, isNotUndefined, isNumber, isRecord, isString, isUndefined } from "@wistia/type-guards";
|
|
14
14
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
15
15
|
import { Toaster, toast } from "sonner";
|
|
16
|
-
import { isPast } from "date-fns/isPast";
|
|
17
|
-
import { isValid } from "date-fns/isValid";
|
|
18
|
-
import { parse } from "date-fns/parse";
|
|
19
|
-
import { startOfDay } from "date-fns/startOfDay";
|
|
20
|
-
import { startOfToday } from "date-fns/startOfToday";
|
|
21
|
-
import { startOfTomorrow } from "date-fns/startOfTomorrow";
|
|
22
16
|
import { getValueAndUnit } from "polished";
|
|
23
17
|
import { useFilePicker as useFilePicker$1, useImperativeFilePicker as useImperativeFilePicker$1 } from "use-file-picker";
|
|
24
18
|
import { FileAmountLimitValidator, FileSizeValidator, FileTypeValidator, ImageDimensionsValidator, PersistentFileAmountLimitValidator } from "use-file-picker/validators";
|
|
@@ -112,6 +106,10 @@ const GlobalStyle = createGlobalStyle`
|
|
|
112
106
|
* 1. Without this fonts are too heavy weight in OS X Firefox
|
|
113
107
|
* 2. Design decision
|
|
114
108
|
3. See: https://allthingssmitty.com/2020/05/11/css-fix-for-100vh-in-mobile-webkit/
|
|
109
|
+
4. Avoid typographic orphans and awkward line breaks. 'text-wrap' is inherited,
|
|
110
|
+
so this becomes the default for all text. Guarded by '@supports' because
|
|
111
|
+
'pretty' is not Baseline yet; browsers without it keep the initial
|
|
112
|
+
'text-wrap: wrap' behavior, so no polyfill is needed.
|
|
115
113
|
*/
|
|
116
114
|
body {
|
|
117
115
|
-moz-osx-font-smoothing: grayscale; /* 1 */
|
|
@@ -119,6 +117,10 @@ const GlobalStyle = createGlobalStyle`
|
|
|
119
117
|
line-height: 1.5; /* 2 */
|
|
120
118
|
min-height: 100vh; /* 3 */
|
|
121
119
|
min-height: -webkit-fill-available; /* 3 */
|
|
120
|
+
|
|
121
|
+
@supports (text-wrap: pretty) {
|
|
122
|
+
text-wrap: pretty; /* 4 */
|
|
123
|
+
}
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
/* Remove default margin in favour of better control in authored CSS */
|
|
@@ -736,17 +738,69 @@ const MONTH_NAMES = [
|
|
|
736
738
|
"November",
|
|
737
739
|
"December"
|
|
738
740
|
];
|
|
739
|
-
const
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
741
|
+
const MONTH_ABBREVIATIONS = MONTH_NAMES.map((name) => name.slice(0, 3));
|
|
742
|
+
const startOfDay = (date) => {
|
|
743
|
+
const result = new Date(date);
|
|
744
|
+
result.setHours(0, 0, 0, 0);
|
|
745
|
+
return result;
|
|
746
|
+
};
|
|
747
|
+
const startOfToday = () => startOfDay(/* @__PURE__ */ new Date());
|
|
748
|
+
const startOfTomorrow = () => {
|
|
749
|
+
const tomorrow = startOfToday();
|
|
750
|
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
751
|
+
return tomorrow;
|
|
752
|
+
};
|
|
753
|
+
const monthIndexIn = (names, value) => names.findIndex((name) => name.toLowerCase() === value.toLowerCase());
|
|
754
|
+
const toNumberOrUndefined = (value) => value === void 0 ? void 0 : Number(value);
|
|
755
|
+
const DATE_PATTERNS = [
|
|
756
|
+
{
|
|
757
|
+
regex: new RegExp(`^(${MONTH_ABBREVIATIONS.join("|")}) (\\d{1,2})(?:, (\\d{1,4}))?$`, "i"),
|
|
758
|
+
toParts: ([, month, day, year]) => ({
|
|
759
|
+
monthIndex: monthIndexIn(MONTH_ABBREVIATIONS, month ?? ""),
|
|
760
|
+
day: Number(day),
|
|
761
|
+
year: toNumberOrUndefined(year)
|
|
762
|
+
})
|
|
763
|
+
},
|
|
764
|
+
{
|
|
765
|
+
regex: new RegExp(`^(${MONTH_NAMES.join("|")}) (\\d{1,2})(?:, (\\d{1,4}))?$`, "i"),
|
|
766
|
+
toParts: ([, month, day, year]) => ({
|
|
767
|
+
monthIndex: monthIndexIn(MONTH_NAMES, month ?? ""),
|
|
768
|
+
day: Number(day),
|
|
769
|
+
year: toNumberOrUndefined(year)
|
|
770
|
+
})
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
regex: /^(\d{1,2})\/(\d{1,2})(?:\/(\d{1,4}))?$/,
|
|
774
|
+
toParts: ([, month, day, year]) => ({
|
|
775
|
+
monthIndex: Number(month) - 1,
|
|
776
|
+
day: Number(day),
|
|
777
|
+
year: toNumberOrUndefined(year)
|
|
778
|
+
})
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
regex: /^(\d{1,2})-(\d{1,2})(?:-(\d{1,4}))?$/,
|
|
782
|
+
toParts: ([, month, day, year]) => ({
|
|
783
|
+
monthIndex: Number(month) - 1,
|
|
784
|
+
day: Number(day),
|
|
785
|
+
year: toNumberOrUndefined(year)
|
|
786
|
+
})
|
|
787
|
+
},
|
|
788
|
+
{
|
|
789
|
+
regex: /^(\d{1,4})-(\d{1,2})-(\d{1,2})$/,
|
|
790
|
+
toParts: ([, year, month, day]) => ({
|
|
791
|
+
monthIndex: Number(month) - 1,
|
|
792
|
+
day: Number(day),
|
|
793
|
+
year: Number(year)
|
|
794
|
+
})
|
|
795
|
+
}
|
|
749
796
|
];
|
|
797
|
+
const toValidDate = ({ monthIndex, day, year }, referenceDate) => {
|
|
798
|
+
if (year === 0) return null;
|
|
799
|
+
const resolvedYear = year ?? referenceDate.getFullYear();
|
|
800
|
+
const date = new Date(referenceDate.getFullYear(), 0, 1);
|
|
801
|
+
date.setFullYear(resolvedYear, monthIndex, day);
|
|
802
|
+
return date.getFullYear() === resolvedYear && date.getMonth() === monthIndex && date.getDate() === day ? date : null;
|
|
803
|
+
};
|
|
750
804
|
const parseDateString = (str) => {
|
|
751
805
|
const trimmed = str.trim();
|
|
752
806
|
if (!trimmed) return null;
|
|
@@ -757,14 +811,19 @@ const parseDateString = (str) => {
|
|
|
757
811
|
if (monthIndex !== -1) {
|
|
758
812
|
const today = startOfToday();
|
|
759
813
|
let date = new Date(today.getFullYear(), monthIndex, 1);
|
|
760
|
-
if (
|
|
761
|
-
return
|
|
814
|
+
if (date.getTime() < Date.now()) date = new Date(today.getFullYear() + 1, monthIndex, 1);
|
|
815
|
+
return date;
|
|
762
816
|
}
|
|
763
817
|
const referenceDate = /* @__PURE__ */ new Date();
|
|
764
|
-
|
|
765
|
-
|
|
818
|
+
for (const { regex, toParts } of DATE_PATTERNS) {
|
|
819
|
+
const match = trimmed.match(regex);
|
|
820
|
+
if (match) {
|
|
821
|
+
const parsed = toValidDate(toParts(match), referenceDate);
|
|
822
|
+
if (parsed !== null) return parsed;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
766
825
|
const native = new Date(trimmed);
|
|
767
|
-
if (
|
|
826
|
+
if (!Number.isNaN(native.getTime())) return startOfDay(native);
|
|
768
827
|
return null;
|
|
769
828
|
};
|
|
770
829
|
//#endregion
|
|
@@ -811,7 +870,7 @@ const getLocalDateParts = (date) => {
|
|
|
811
870
|
//#region src/helpers/dateTime/differenceInCalendarDays.ts
|
|
812
871
|
/**
|
|
813
872
|
* Returns the difference in calendar days between two dates in local time,
|
|
814
|
-
* ignoring the time of day.
|
|
873
|
+
* ignoring the time of day.
|
|
815
874
|
*
|
|
816
875
|
* @param {Date|number} dateLeft - The later date (or timestamp).
|
|
817
876
|
* @param {Date|number} dateRight - The earlier date (or timestamp).
|
|
@@ -1426,7 +1485,7 @@ const useFocusTrap = (active = true, options = {}) => {
|
|
|
1426
1485
|
setTimeout(() => {
|
|
1427
1486
|
if (node.ownerDocument) processNode(node);
|
|
1428
1487
|
if (!node.ownerDocument) console.warn("[useFocusTrap]: The focus trap is not part of the DOM yet, so it is unable to correctly set focus. Make sure to render the ref node.", node);
|
|
1429
|
-
});
|
|
1488
|
+
}, 0);
|
|
1430
1489
|
ref.current = node;
|
|
1431
1490
|
} else ref.current = null;
|
|
1432
1491
|
}, [
|
|
@@ -5347,6 +5406,9 @@ const IconComponent = ({ useInlineStyles = true, invertColor, colorScheme = "inh
|
|
|
5347
5406
|
});
|
|
5348
5407
|
};
|
|
5349
5408
|
IconComponent.displayName = "Icon_UI";
|
|
5409
|
+
/**
|
|
5410
|
+
* An `Icon` displays a visual symbol to represent an action, concept, or entity, rendering the SVG registered for its `type` at a fixed or responsive `size`.
|
|
5411
|
+
*/
|
|
5350
5412
|
const Icon = IconComponent;
|
|
5351
5413
|
//#endregion
|
|
5352
5414
|
//#region src/components/Link/Link.tsx
|
|
@@ -5928,6 +5990,9 @@ const StyledImage = styled.img`
|
|
|
5928
5990
|
object-fit: ${({ $objFit }) => $objFit};
|
|
5929
5991
|
object-position: ${({ $objPosition }) => $objPosition};
|
|
5930
5992
|
`;
|
|
5993
|
+
/**
|
|
5994
|
+
* An `Image` displays a photo or graphic inline, with controls for border radius, object fit, and how it fills its container. It lazy-loads by default via the native `loading` attribute.
|
|
5995
|
+
*/
|
|
5931
5996
|
const Image = ({ src, alt, borderRadius, fill: fillContainer = false, fit: objFit, loading = "lazy", position: objPosition, onLoad, onError, ...props }) => /* @__PURE__ */ jsx(StyledImage, {
|
|
5932
5997
|
$borderRadius: borderRadius,
|
|
5933
5998
|
$fillContainer: fillContainer,
|
|
@@ -7285,6 +7350,9 @@ const StyledHiddenCheckboxInput = styled.input`
|
|
|
7285
7350
|
${visuallyHiddenStyle}
|
|
7286
7351
|
position: relative;
|
|
7287
7352
|
`;
|
|
7353
|
+
/**
|
|
7354
|
+
* A `Checkbox` lets users select one or more options from a set, or toggle a single option on or off. It supports both standalone controlled usage and grouped usage via `CheckboxGroup`.
|
|
7355
|
+
*/
|
|
7288
7356
|
const Checkbox = ({ checked, disabled = false, id, label, description, name, onChange, size = "md", value, required = false, hideLabel = false, ref, ...props }) => {
|
|
7289
7357
|
const generatedId = useId();
|
|
7290
7358
|
const computedId = isNonEmptyString(id) ? id : `wistia-ui-checkbox-${generatedId}`;
|
|
@@ -8550,6 +8618,9 @@ const StyledSwitchThumb = styled.div`
|
|
|
8550
8618
|
const StyledHiddenSwitchInput = styled.input`
|
|
8551
8619
|
${visuallyHiddenStyle}
|
|
8552
8620
|
`;
|
|
8621
|
+
/**
|
|
8622
|
+
* A `Switch` allows users to toggle between two mutually exclusive states, such as on and off.
|
|
8623
|
+
*/
|
|
8553
8624
|
const Switch = ({ align = "left", checked, disabled = false, id, label, description, name, onChange, size = "md", value, required = false, hideLabel = false, ref, ...props }) => {
|
|
8554
8625
|
const generatedId = useId();
|
|
8555
8626
|
const computedId = isNonEmptyString(id) ? id : `wistia-ui-switch-${generatedId}`;
|
|
@@ -9766,6 +9837,9 @@ const defaultDisplayValues = (values, onRemove) => {
|
|
|
9766
9837
|
onClickRemoveLabel: `Remove ${selectedValue}`
|
|
9767
9838
|
}, selectedValue));
|
|
9768
9839
|
};
|
|
9840
|
+
/**
|
|
9841
|
+
* A `Combobox` is a searchable single- or multi-select input. Users can filter options by typing, and selected values in multi-select mode are displayed as removable `Tag` components.
|
|
9842
|
+
*/
|
|
9769
9843
|
const Combobox = ({ placeholder, value, onChange, searchValue, onSearchValueChange, displayValues = defaultDisplayValues, children, flipPopover = true, fullWidth = true }) => {
|
|
9770
9844
|
const [isOpen, setIsOpen] = useState(false);
|
|
9771
9845
|
const [isPending, startTransition] = useTransition();
|
|
@@ -9991,13 +10065,13 @@ const ContextMenuPopup = styled(Menu$1.Popup)`
|
|
|
9991
10065
|
${menuContentCss}
|
|
9992
10066
|
outline: none;
|
|
9993
10067
|
`;
|
|
10068
|
+
const NOOP$4 = () => null;
|
|
9994
10069
|
/**
|
|
9995
10070
|
* The ContextMenu is an extended implementation of the [Menu](/components/Menu) component that allows for right-click context menus.
|
|
9996
10071
|
* It can be used in two ways:
|
|
9997
10072
|
* 1. By providing a `triggerRef`, which will render the menu when the referenced element is right-clicked.
|
|
9998
10073
|
* 2. By providing a `position` prop, which will render the menu at the specified coordinates.
|
|
9999
10074
|
*/
|
|
10000
|
-
const NOOP$4 = () => null;
|
|
10001
10075
|
const ContextMenu = ({ position, triggerRef, children, side = "bottom", onRequestClose = NOOP$4, compact = false }) => {
|
|
10002
10076
|
const [isRightClicked, setIsRightClicked] = useState(false);
|
|
10003
10077
|
const [menuPosition, setMenuPosition] = useState(position ?? {
|
|
@@ -12506,6 +12580,9 @@ const GridComponent = ({ ref, children, columns = "auto", minChildWidth = "auto"
|
|
|
12506
12580
|
children
|
|
12507
12581
|
});
|
|
12508
12582
|
};
|
|
12583
|
+
/**
|
|
12584
|
+
* A `Grid` arranges its children in a CSS grid layout with configurable `columns`, `gap`, and responsive breakpoint support.
|
|
12585
|
+
*/
|
|
12509
12586
|
const Grid = makePolymorphic(GridComponent);
|
|
12510
12587
|
//#endregion
|
|
12511
12588
|
//#region src/components/PreviewCard/PreviewCard.tsx
|
|
@@ -13514,6 +13591,9 @@ const keyToString = (key) => {
|
|
|
13514
13591
|
default: return key.toUpperCase();
|
|
13515
13592
|
}
|
|
13516
13593
|
};
|
|
13594
|
+
/**
|
|
13595
|
+
* A `KeyboardShortcut` displays one or more keyboard keys with an optional label, rendering each key in a styled `kbd` element. Platform-specific keys like `Cmd`/`Meta` are rendered with the appropriate symbol for the detected operating system.
|
|
13596
|
+
*/
|
|
13517
13597
|
const KeyboardShortcut = ({ label, keyboardKeys, fullWidth = false, ...otherProps }) => /* @__PURE__ */ jsxs(StyledKeyboardShortcut, {
|
|
13518
13598
|
$fullWidth: fullWidth,
|
|
13519
13599
|
...otherProps,
|
|
@@ -13634,6 +13714,9 @@ const renderListFromArray = (listItems, variant, otherProps) => {
|
|
|
13634
13714
|
return /* @__PURE__ */ jsx(ListItem, { children: item }, key);
|
|
13635
13715
|
}), variant, otherProps);
|
|
13636
13716
|
};
|
|
13717
|
+
/**
|
|
13718
|
+
* A `List` groups related items in bulleted, ordered, or separator-based layouts, composed with `ListItem` children or a flat/nested `items` array.
|
|
13719
|
+
*/
|
|
13637
13720
|
const List = ({ children, items, variant, ...otherProps }) => {
|
|
13638
13721
|
const listVariant = variant ?? "bullets";
|
|
13639
13722
|
if (isNotNil(children)) {
|
|
@@ -14749,6 +14832,9 @@ const StyledRadioInput = styled.div`
|
|
|
14749
14832
|
const StyledHiddenRadioInput = styled.input`
|
|
14750
14833
|
${visuallyHiddenStyle}
|
|
14751
14834
|
`;
|
|
14835
|
+
/**
|
|
14836
|
+
* A `Radio` lets users select exactly one option from a visible set of choices.
|
|
14837
|
+
*/
|
|
14752
14838
|
const Radio = ({ checked, disabled = false, id, label, description, name, onChange, size = "md", value = "false", required = false, hideLabel = false, ref, ...props }) => {
|
|
14753
14839
|
const generatedId = useId();
|
|
14754
14840
|
const computedId = isNonEmptyString(id) ? id : `wistia-ui-radio-${generatedId}`;
|
|
@@ -15032,6 +15118,9 @@ const RadioCardDefaultLayout = ({ icon, label, description, showIndicator = true
|
|
|
15032
15118
|
RadioCardDefaultLayout.displayName = "RadioCardDefaultLayout_UI";
|
|
15033
15119
|
//#endregion
|
|
15034
15120
|
//#region src/components/RadioCard/RadioCard.tsx
|
|
15121
|
+
/**
|
|
15122
|
+
* A `RadioCard` lets users select exactly one option from a set of visually rich, card-based choices.
|
|
15123
|
+
*/
|
|
15035
15124
|
const RadioCard = ({ icon, label, description, showIndicator, isGated, children, ref, ...rootProps }) => {
|
|
15036
15125
|
return /* @__PURE__ */ jsx(RadioCardRoot, {
|
|
15037
15126
|
ref,
|
|
@@ -15652,6 +15741,9 @@ const StyledSidebar = styled.nav`
|
|
|
15652
15741
|
overflow: hidden;
|
|
15653
15742
|
border-right: 1px solid var(--wui-color-border);
|
|
15654
15743
|
`;
|
|
15744
|
+
/**
|
|
15745
|
+
* The `Sidebar` provides vertical navigation with a composable header, scrollable content area, and footer.
|
|
15746
|
+
*/
|
|
15655
15747
|
const Sidebar = ({ children, ref, ...props }) => {
|
|
15656
15748
|
return /* @__PURE__ */ jsx(StyledSidebar, {
|
|
15657
15749
|
ref,
|
|
@@ -15895,6 +15987,9 @@ const StyledSliderThumb = styled(Slider$1.Thumb)`
|
|
|
15895
15987
|
}
|
|
15896
15988
|
`;
|
|
15897
15989
|
const DEFAULT_INITIAL_VALUE = [0];
|
|
15990
|
+
/**
|
|
15991
|
+
* A `Slider` lets users select a value or range from a continuous scale via a draggable thumb.
|
|
15992
|
+
*/
|
|
15898
15993
|
const Slider = ({ "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, disabled = false, initialValue = DEFAULT_INITIAL_VALUE, max = 100, min = 0, onChange, onValueCommitted, step = 1, value, "data-testid": dataTestId = "ui-slider", ...otherProps }) => {
|
|
15899
15994
|
if (!(isNonEmptyString(ariaLabel) || isNonEmptyString(ariaLabelledby))) throw new Error("UI Slider: Sliders should have an accessible name. Add a label using the aria-label or aria-labelledby prop.");
|
|
15900
15995
|
const values = value ?? initialValue;
|
|
@@ -16122,6 +16217,9 @@ const useTabsValue = () => {
|
|
|
16122
16217
|
};
|
|
16123
16218
|
//#endregion
|
|
16124
16219
|
//#region src/components/Tabs/Tabs.tsx
|
|
16220
|
+
/**
|
|
16221
|
+
* The `Tabs` component lets users switch between panels of content. It is composed from the `TabsList`, `TabsTrigger`, and `TabsContent` subcomponents.
|
|
16222
|
+
*/
|
|
16125
16223
|
const Tabs = ({ children, value: valueProp, onValueChange: onValueChangeProp, defaultValue, ...props }) => {
|
|
16126
16224
|
const [internalValue, setInternalValue] = useState(valueProp ?? defaultValue);
|
|
16127
16225
|
const isControlled = isNotNil(valueProp);
|