medusa-plugin-reviews-and-ratings
Version:
Medusa plugin to add product reviews and ratings functionality in the project.
3,036 lines • 124 kB
JavaScript
import { jsxs, jsx, Fragment as Fragment$1 } from 'react/jsx-runtime';
import { useAdminCustomQuery } from 'medusa-react';
import { Text, IconButton, useToggleState, Table, Avatar } from '@medusajs/ui';
import { StarSolid, XMark, ChevronLeft, ChevronRight, ArrowLeftMini, ArrowRightMini } from '@medusajs/icons';
import * as React from 'react';
import React__default, { useCallback, createContext, useMemo, createElement, useContext, useLayoutEffect, useRef, useEffect, useState, forwardRef, Children, isValidElement, cloneElement, Fragment, useReducer } from 'react';
import Carousel from 'react-gallery-carousel';
import $7SXl2$reactdom, { flushSync } from 'react-dom';
const ProgressBar = ({
star,
barPercentage,
total
}) => {
return /* @__PURE__ */ jsxs("div", { className: "w-full flex items-center gap-3", children: [
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
/* @__PURE__ */ jsx(Text, { className: "text-grey-50", children: star }),
/* @__PURE__ */ jsx("div", { className: "text-yellow-50", children: /* @__PURE__ */ jsx(StarSolid, {}) })
] }),
/* @__PURE__ */ jsx("div", { className: "w-full h-2 bg-gradient-to-r from-gray-200 to-gray-400 rounded-md", children: /* @__PURE__ */ jsx(
"div",
{
className: "bg-gradient-to-r from-gray-500 to-gray-700 h-2 rounded-md",
style: { width: barPercentage }
}
) }),
/* @__PURE__ */ jsx(Text, { className: "text-grey-50", children: total })
] });
};
function RatingOverview({
starWiseData,
averageRatings,
totalRatings
}) {
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
/* @__PURE__ */ jsx("h2", { className: "inter-large-semibold", children: "Ratings overview" }),
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
/* @__PURE__ */ jsx("h3", { className: "inter-base-regular text-grey-50", children: "Average rating" }),
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
/* @__PURE__ */ jsx("div", { className: "text-yellow-50 inter-base-regular", children: /* @__PURE__ */ jsx(StarSolid, {}) }),
/* @__PURE__ */ jsxs("h3", { className: "inter-base-regular text-grey-50", children: [
averageRatings == null ? void 0 : averageRatings.toFixed(1),
" out of 5"
] })
] })
] }),
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
/* @__PURE__ */ jsx("h3", { className: "inter-base-regular text-grey-50", children: "Total ratings" }),
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: /* @__PURE__ */ jsx("h3", { className: "inter-base-regular text-grey-50", children: totalRatings }) })
] }),
starWiseData && Object.entries(starWiseData).map(([key, value], index) => /* @__PURE__ */ jsx(
ProgressBar,
{
star: index + 1,
barPercentage: `${value.bar_percentage}%`,
total: value.total
},
key
)).reverse()
] });
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function $e42e1063c40fb3ef$export$b9ecd428b558ff10(originalEventHandler, ourEventHandler, { checkForDefaultPrevented: checkForDefaultPrevented = true } = {}) {
return function handleEvent(event) {
originalEventHandler === null || originalEventHandler === void 0 || originalEventHandler(event);
if (checkForDefaultPrevented === false || !event.defaultPrevented) return ourEventHandler === null || ourEventHandler === void 0 ? void 0 : ourEventHandler(event);
};
}
/**
* Set a given ref to a given value
* This utility takes care of different types of refs: callback refs and RefObject(s)
*/ function $6ed0406888f73fc4$var$setRef(ref, value) {
if (typeof ref === 'function') ref(value);
else if (ref !== null && ref !== undefined) ref.current = value;
}
/**
* A utility to compose multiple refs together
* Accepts callback refs and RefObject(s)
*/ function $6ed0406888f73fc4$export$43e446d32b3d21af(...refs) {
return (node)=>refs.forEach((ref)=>$6ed0406888f73fc4$var$setRef(ref, node)
)
;
}
/**
* A custom hook that composes multiple refs
* Accepts callback refs and RefObject(s)
*/ function $6ed0406888f73fc4$export$c7b2cbe3552a0d05(...refs) {
// eslint-disable-next-line react-hooks/exhaustive-deps
return useCallback($6ed0406888f73fc4$export$43e446d32b3d21af(...refs), refs);
}
/* -------------------------------------------------------------------------------------------------
* createContextScope
* -----------------------------------------------------------------------------------------------*/ function $c512c27ab02ef895$export$50c7b4e9d9f19c1(scopeName, createContextScopeDeps = []) {
let defaultContexts = [];
/* -----------------------------------------------------------------------------------------------
* createContext
* ---------------------------------------------------------------------------------------------*/ function $c512c27ab02ef895$export$fd42f52fd3ae1109(rootComponentName, defaultContext) {
const BaseContext = /*#__PURE__*/ createContext(defaultContext);
const index = defaultContexts.length;
defaultContexts = [
...defaultContexts,
defaultContext
];
function Provider(props) {
const { scope: scope , children: children , ...context } = props;
const Context = (scope === null || scope === void 0 ? void 0 : scope[scopeName][index]) || BaseContext; // Only re-memoize when prop values change
// eslint-disable-next-line react-hooks/exhaustive-deps
const value = useMemo(()=>context
, Object.values(context));
return /*#__PURE__*/ createElement(Context.Provider, {
value: value
}, children);
}
function useContext$1(consumerName, scope) {
const Context = (scope === null || scope === void 0 ? void 0 : scope[scopeName][index]) || BaseContext;
const context = useContext(Context);
if (context) return context;
if (defaultContext !== undefined) return defaultContext; // if a defaultContext wasn't specified, it's a required context.
throw new Error(`\`${consumerName}\` must be used within \`${rootComponentName}\``);
}
Provider.displayName = rootComponentName + 'Provider';
return [
Provider,
useContext$1
];
}
/* -----------------------------------------------------------------------------------------------
* createScope
* ---------------------------------------------------------------------------------------------*/ const createScope = ()=>{
const scopeContexts = defaultContexts.map((defaultContext)=>{
return /*#__PURE__*/ createContext(defaultContext);
});
return function useScope(scope) {
const contexts = (scope === null || scope === void 0 ? void 0 : scope[scopeName]) || scopeContexts;
return useMemo(()=>({
[`__scope${scopeName}`]: {
...scope,
[scopeName]: contexts
}
})
, [
scope,
contexts
]);
};
};
createScope.scopeName = scopeName;
return [
$c512c27ab02ef895$export$fd42f52fd3ae1109,
$c512c27ab02ef895$var$composeContextScopes(createScope, ...createContextScopeDeps)
];
}
/* -------------------------------------------------------------------------------------------------
* composeContextScopes
* -----------------------------------------------------------------------------------------------*/ function $c512c27ab02ef895$var$composeContextScopes(...scopes) {
const baseScope = scopes[0];
if (scopes.length === 1) return baseScope;
const createScope1 = ()=>{
const scopeHooks = scopes.map((createScope)=>({
useScope: createScope(),
scopeName: createScope.scopeName
})
);
return function useComposedScopes(overrideScopes) {
const nextScopes1 = scopeHooks.reduce((nextScopes, { useScope: useScope , scopeName: scopeName })=>{
// We are calling a hook inside a callback which React warns against to avoid inconsistent
// renders, however, scoping doesn't have render side effects so we ignore the rule.
// eslint-disable-next-line react-hooks/rules-of-hooks
const scopeProps = useScope(overrideScopes);
const currentScope = scopeProps[`__scope${scopeName}`];
return {
...nextScopes,
...currentScope
};
}, {});
return useMemo(()=>({
[`__scope${baseScope.scopeName}`]: nextScopes1
})
, [
nextScopes1
]);
};
};
createScope1.scopeName = baseScope.scopeName;
return createScope1;
}
/**
* On the server, React emits a warning when calling `useLayoutEffect`.
* This is because neither `useLayoutEffect` nor `useEffect` run on the server.
* We use this safe version which suppresses the warning by replacing it with a noop on the server.
*
* See: https://reactjs.org/docs/hooks-reference.html#uselayouteffect
*/ const $9f79659886946c16$export$e5c5a5f917a5871c = Boolean(globalThis === null || globalThis === void 0 ? void 0 : globalThis.document) ? useLayoutEffect : ()=>{};
const $1746a345f3d73bb7$var$useReactId = React['useId'.toString()] || (()=>undefined
);
let $1746a345f3d73bb7$var$count = 0;
function $1746a345f3d73bb7$export$f680877a34711e37(deterministicId) {
const [id, setId] = React.useState($1746a345f3d73bb7$var$useReactId()); // React versions older than 18 will have client-side ids only.
$9f79659886946c16$export$e5c5a5f917a5871c(()=>{
if (!deterministicId) setId((reactId)=>reactId !== null && reactId !== void 0 ? reactId : String($1746a345f3d73bb7$var$count++)
);
}, [
deterministicId
]);
return deterministicId || (id ? `radix-${id}` : '');
}
/**
* A custom hook that converts a callback to a ref to avoid triggering re-renders when passed as a
* prop or avoid re-executing effects when passed as a dependency
*/ function $b1b2314f5f9a1d84$export$25bec8c6f54ee79a(callback) {
const callbackRef = useRef(callback);
useEffect(()=>{
callbackRef.current = callback;
}); // https://github.com/facebook/react/issues/19240
return useMemo(()=>(...args)=>{
var _callbackRef$current;
return (_callbackRef$current = callbackRef.current) === null || _callbackRef$current === void 0 ? void 0 : _callbackRef$current.call(callbackRef, ...args);
}
, []);
}
function $71cd76cc60e0454e$export$6f32135080cb4c3({ prop: prop , defaultProp: defaultProp , onChange: onChange = ()=>{} }) {
const [uncontrolledProp, setUncontrolledProp] = $71cd76cc60e0454e$var$useUncontrolledState({
defaultProp: defaultProp,
onChange: onChange
});
const isControlled = prop !== undefined;
const value1 = isControlled ? prop : uncontrolledProp;
const handleChange = $b1b2314f5f9a1d84$export$25bec8c6f54ee79a(onChange);
const setValue = useCallback((nextValue)=>{
if (isControlled) {
const setter = nextValue;
const value = typeof nextValue === 'function' ? setter(prop) : nextValue;
if (value !== prop) handleChange(value);
} else setUncontrolledProp(nextValue);
}, [
isControlled,
prop,
setUncontrolledProp,
handleChange
]);
return [
value1,
setValue
];
}
function $71cd76cc60e0454e$var$useUncontrolledState({ defaultProp: defaultProp , onChange: onChange }) {
const uncontrolledState = useState(defaultProp);
const [value] = uncontrolledState;
const prevValueRef = useRef(value);
const handleChange = $b1b2314f5f9a1d84$export$25bec8c6f54ee79a(onChange);
useEffect(()=>{
if (prevValueRef.current !== value) {
handleChange(value);
prevValueRef.current = value;
}
}, [
value,
prevValueRef,
handleChange
]);
return uncontrolledState;
}
/* -------------------------------------------------------------------------------------------------
* Slot
* -----------------------------------------------------------------------------------------------*/ const $5e63c961fc1ce211$export$8c6ed5c666ac1360 = /*#__PURE__*/ forwardRef((props, forwardedRef)=>{
const { children: children , ...slotProps } = props;
const childrenArray = Children.toArray(children);
const slottable = childrenArray.find($5e63c961fc1ce211$var$isSlottable);
if (slottable) {
// the new element to render is the one passed as a child of `Slottable`
const newElement = slottable.props.children;
const newChildren = childrenArray.map((child)=>{
if (child === slottable) {
// because the new element will be the one rendered, we are only interested
// in grabbing its children (`newElement.props.children`)
if (Children.count(newElement) > 1) return Children.only(null);
return /*#__PURE__*/ isValidElement(newElement) ? newElement.props.children : null;
} else return child;
});
return /*#__PURE__*/ createElement($5e63c961fc1ce211$var$SlotClone, _extends({}, slotProps, {
ref: forwardedRef
}), /*#__PURE__*/ isValidElement(newElement) ? /*#__PURE__*/ cloneElement(newElement, undefined, newChildren) : null);
}
return /*#__PURE__*/ createElement($5e63c961fc1ce211$var$SlotClone, _extends({}, slotProps, {
ref: forwardedRef
}), children);
});
$5e63c961fc1ce211$export$8c6ed5c666ac1360.displayName = 'Slot';
/* -------------------------------------------------------------------------------------------------
* SlotClone
* -----------------------------------------------------------------------------------------------*/ const $5e63c961fc1ce211$var$SlotClone = /*#__PURE__*/ forwardRef((props, forwardedRef)=>{
const { children: children , ...slotProps } = props;
if (/*#__PURE__*/ isValidElement(children)) return /*#__PURE__*/ cloneElement(children, {
...$5e63c961fc1ce211$var$mergeProps(slotProps, children.props),
ref: forwardedRef ? $6ed0406888f73fc4$export$43e446d32b3d21af(forwardedRef, children.ref) : children.ref
});
return Children.count(children) > 1 ? Children.only(null) : null;
});
$5e63c961fc1ce211$var$SlotClone.displayName = 'SlotClone';
/* -------------------------------------------------------------------------------------------------
* Slottable
* -----------------------------------------------------------------------------------------------*/ const $5e63c961fc1ce211$export$d9f1ccf0bdb05d45 = ({ children: children })=>{
return /*#__PURE__*/ createElement(Fragment, null, children);
};
/* ---------------------------------------------------------------------------------------------- */ function $5e63c961fc1ce211$var$isSlottable(child) {
return /*#__PURE__*/ isValidElement(child) && child.type === $5e63c961fc1ce211$export$d9f1ccf0bdb05d45;
}
function $5e63c961fc1ce211$var$mergeProps(slotProps, childProps) {
// all child props should override
const overrideProps = {
...childProps
};
for(const propName in childProps){
const slotPropValue = slotProps[propName];
const childPropValue = childProps[propName];
const isHandler = /^on[A-Z]/.test(propName);
if (isHandler) {
// if the handler exists on both, we compose them
if (slotPropValue && childPropValue) overrideProps[propName] = (...args)=>{
childPropValue(...args);
slotPropValue(...args);
};
else if (slotPropValue) overrideProps[propName] = slotPropValue;
} else if (propName === 'style') overrideProps[propName] = {
...slotPropValue,
...childPropValue
};
else if (propName === 'className') overrideProps[propName] = [
slotPropValue,
childPropValue
].filter(Boolean).join(' ');
}
return {
...slotProps,
...overrideProps
};
}
const $8927f6f2acc4f386$var$NODES = [
'a',
'button',
'div',
'form',
'h2',
'h3',
'img',
'input',
'label',
'li',
'nav',
'ol',
'p',
'span',
'svg',
'ul'
]; // Temporary while we await merge of this fix:
// https://github.com/DefinitelyTyped/DefinitelyTyped/pull/55396
// prettier-ignore
/* -------------------------------------------------------------------------------------------------
* Primitive
* -----------------------------------------------------------------------------------------------*/ const $8927f6f2acc4f386$export$250ffa63cdc0d034 = $8927f6f2acc4f386$var$NODES.reduce((primitive, node)=>{
const Node = /*#__PURE__*/ forwardRef((props, forwardedRef)=>{
const { asChild: asChild , ...primitiveProps } = props;
const Comp = asChild ? $5e63c961fc1ce211$export$8c6ed5c666ac1360 : node;
useEffect(()=>{
window[Symbol.for('radix-ui')] = true;
}, []);
return /*#__PURE__*/ createElement(Comp, _extends({}, primitiveProps, {
ref: forwardedRef
}));
});
Node.displayName = `Primitive.${node}`;
return {
...primitive,
[node]: Node
};
}, {});
/* -------------------------------------------------------------------------------------------------
* Utils
* -----------------------------------------------------------------------------------------------*/ /**
* Flush custom event dispatch
* https://github.com/radix-ui/primitives/pull/1378
*
* React batches *all* event handlers since version 18, this introduces certain considerations when using custom event types.
*
* Internally, React prioritises events in the following order:
* - discrete
* - continuous
* - default
*
* https://github.com/facebook/react/blob/a8a4742f1c54493df00da648a3f9d26e3db9c8b5/packages/react-dom/src/events/ReactDOMEventListener.js#L294-L350
*
* `discrete` is an important distinction as updates within these events are applied immediately.
* React however, is not able to infer the priority of custom event types due to how they are detected internally.
* Because of this, it's possible for updates from custom events to be unexpectedly batched when
* dispatched by another `discrete` event.
*
* In order to ensure that updates from custom events are applied predictably, we need to manually flush the batch.
* This utility should be used when dispatching a custom event from within another `discrete` event, this utility
* is not nessesary when dispatching known event types, or if dispatching a custom type inside a non-discrete event.
* For example:
*
* dispatching a known click 👎
* target.dispatchEvent(new Event(‘click’))
*
* dispatching a custom type within a non-discrete event 👎
* onScroll={(event) => event.target.dispatchEvent(new CustomEvent(‘customType’))}
*
* dispatching a custom type within a `discrete` event 👍
* onPointerDown={(event) => dispatchDiscreteCustomEvent(event.target, new CustomEvent(‘customType’))}
*
* Note: though React classifies `focus`, `focusin` and `focusout` events as `discrete`, it's not recommended to use
* this utility with them. This is because it's possible for those handlers to be called implicitly during render
* e.g. when focus is within a component as it is unmounted, or when managing focus on mount.
*/ function $8927f6f2acc4f386$export$6d1a0317bde7de7f(target, event) {
if (target) flushSync(()=>target.dispatchEvent(event)
);
}
/**
* Listens for when the escape key is down
*/ function $addc16e1bbe58fd0$export$3a72a57244d6e765(onEscapeKeyDownProp, ownerDocument = globalThis === null || globalThis === void 0 ? void 0 : globalThis.document) {
const onEscapeKeyDown = $b1b2314f5f9a1d84$export$25bec8c6f54ee79a(onEscapeKeyDownProp);
useEffect(()=>{
const handleKeyDown = (event)=>{
if (event.key === 'Escape') onEscapeKeyDown(event);
};
ownerDocument.addEventListener('keydown', handleKeyDown);
return ()=>ownerDocument.removeEventListener('keydown', handleKeyDown)
;
}, [
onEscapeKeyDown,
ownerDocument
]);
}
const $5cb92bef7577960e$var$CONTEXT_UPDATE = 'dismissableLayer.update';
const $5cb92bef7577960e$var$POINTER_DOWN_OUTSIDE = 'dismissableLayer.pointerDownOutside';
const $5cb92bef7577960e$var$FOCUS_OUTSIDE = 'dismissableLayer.focusOutside';
let $5cb92bef7577960e$var$originalBodyPointerEvents;
const $5cb92bef7577960e$var$DismissableLayerContext = /*#__PURE__*/ createContext({
layers: new Set(),
layersWithOutsidePointerEventsDisabled: new Set(),
branches: new Set()
});
const $5cb92bef7577960e$export$177fb62ff3ec1f22 = /*#__PURE__*/ forwardRef((props, forwardedRef)=>{
var _node$ownerDocument;
const { disableOutsidePointerEvents: disableOutsidePointerEvents = false , onEscapeKeyDown: onEscapeKeyDown , onPointerDownOutside: onPointerDownOutside , onFocusOutside: onFocusOutside , onInteractOutside: onInteractOutside , onDismiss: onDismiss , ...layerProps } = props;
const context = useContext($5cb92bef7577960e$var$DismissableLayerContext);
const [node1, setNode] = useState(null);
const ownerDocument = (_node$ownerDocument = node1 === null || node1 === void 0 ? void 0 : node1.ownerDocument) !== null && _node$ownerDocument !== void 0 ? _node$ownerDocument : globalThis === null || globalThis === void 0 ? void 0 : globalThis.document;
const [, force] = useState({});
const composedRefs = $6ed0406888f73fc4$export$c7b2cbe3552a0d05(forwardedRef, (node)=>setNode(node)
);
const layers = Array.from(context.layers);
const [highestLayerWithOutsidePointerEventsDisabled] = [
...context.layersWithOutsidePointerEventsDisabled
].slice(-1); // prettier-ignore
const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled); // prettier-ignore
const index = node1 ? layers.indexOf(node1) : -1;
const isBodyPointerEventsDisabled = context.layersWithOutsidePointerEventsDisabled.size > 0;
const isPointerEventsEnabled = index >= highestLayerWithOutsidePointerEventsDisabledIndex;
const pointerDownOutside = $5cb92bef7577960e$var$usePointerDownOutside((event)=>{
const target = event.target;
const isPointerDownOnBranch = [
...context.branches
].some((branch)=>branch.contains(target)
);
if (!isPointerEventsEnabled || isPointerDownOnBranch) return;
onPointerDownOutside === null || onPointerDownOutside === void 0 || onPointerDownOutside(event);
onInteractOutside === null || onInteractOutside === void 0 || onInteractOutside(event);
if (!event.defaultPrevented) onDismiss === null || onDismiss === void 0 || onDismiss();
}, ownerDocument);
const focusOutside = $5cb92bef7577960e$var$useFocusOutside((event)=>{
const target = event.target;
const isFocusInBranch = [
...context.branches
].some((branch)=>branch.contains(target)
);
if (isFocusInBranch) return;
onFocusOutside === null || onFocusOutside === void 0 || onFocusOutside(event);
onInteractOutside === null || onInteractOutside === void 0 || onInteractOutside(event);
if (!event.defaultPrevented) onDismiss === null || onDismiss === void 0 || onDismiss();
}, ownerDocument);
$addc16e1bbe58fd0$export$3a72a57244d6e765((event)=>{
const isHighestLayer = index === context.layers.size - 1;
if (!isHighestLayer) return;
onEscapeKeyDown === null || onEscapeKeyDown === void 0 || onEscapeKeyDown(event);
if (!event.defaultPrevented && onDismiss) {
event.preventDefault();
onDismiss();
}
}, ownerDocument);
useEffect(()=>{
if (!node1) return;
if (disableOutsidePointerEvents) {
if (context.layersWithOutsidePointerEventsDisabled.size === 0) {
$5cb92bef7577960e$var$originalBodyPointerEvents = ownerDocument.body.style.pointerEvents;
ownerDocument.body.style.pointerEvents = 'none';
}
context.layersWithOutsidePointerEventsDisabled.add(node1);
}
context.layers.add(node1);
$5cb92bef7577960e$var$dispatchUpdate();
return ()=>{
if (disableOutsidePointerEvents && context.layersWithOutsidePointerEventsDisabled.size === 1) ownerDocument.body.style.pointerEvents = $5cb92bef7577960e$var$originalBodyPointerEvents;
};
}, [
node1,
ownerDocument,
disableOutsidePointerEvents,
context
]);
/**
* We purposefully prevent combining this effect with the `disableOutsidePointerEvents` effect
* because a change to `disableOutsidePointerEvents` would remove this layer from the stack
* and add it to the end again so the layering order wouldn't be _creation order_.
* We only want them to be removed from context stacks when unmounted.
*/ useEffect(()=>{
return ()=>{
if (!node1) return;
context.layers.delete(node1);
context.layersWithOutsidePointerEventsDisabled.delete(node1);
$5cb92bef7577960e$var$dispatchUpdate();
};
}, [
node1,
context
]);
useEffect(()=>{
const handleUpdate = ()=>force({})
;
document.addEventListener($5cb92bef7577960e$var$CONTEXT_UPDATE, handleUpdate);
return ()=>document.removeEventListener($5cb92bef7577960e$var$CONTEXT_UPDATE, handleUpdate)
;
}, []);
return /*#__PURE__*/ createElement($8927f6f2acc4f386$export$250ffa63cdc0d034.div, _extends({}, layerProps, {
ref: composedRefs,
style: {
pointerEvents: isBodyPointerEventsDisabled ? isPointerEventsEnabled ? 'auto' : 'none' : undefined,
...props.style
},
onFocusCapture: $e42e1063c40fb3ef$export$b9ecd428b558ff10(props.onFocusCapture, focusOutside.onFocusCapture),
onBlurCapture: $e42e1063c40fb3ef$export$b9ecd428b558ff10(props.onBlurCapture, focusOutside.onBlurCapture),
onPointerDownCapture: $e42e1063c40fb3ef$export$b9ecd428b558ff10(props.onPointerDownCapture, pointerDownOutside.onPointerDownCapture)
}));
});
/* -----------------------------------------------------------------------------------------------*/ /**
* Listens for `pointerdown` outside a react subtree. We use `pointerdown` rather than `pointerup`
* to mimic layer dismissing behaviour present in OS.
* Returns props to pass to the node we want to check for outside events.
*/ function $5cb92bef7577960e$var$usePointerDownOutside(onPointerDownOutside, ownerDocument = globalThis === null || globalThis === void 0 ? void 0 : globalThis.document) {
const handlePointerDownOutside = $b1b2314f5f9a1d84$export$25bec8c6f54ee79a(onPointerDownOutside);
const isPointerInsideReactTreeRef = useRef(false);
const handleClickRef = useRef(()=>{});
useEffect(()=>{
const handlePointerDown = (event)=>{
if (event.target && !isPointerInsideReactTreeRef.current) {
const eventDetail = {
originalEvent: event
};
function handleAndDispatchPointerDownOutsideEvent() {
$5cb92bef7577960e$var$handleAndDispatchCustomEvent($5cb92bef7577960e$var$POINTER_DOWN_OUTSIDE, handlePointerDownOutside, eventDetail, {
discrete: true
});
}
/**
* On touch devices, we need to wait for a click event because browsers implement
* a ~350ms delay between the time the user stops touching the display and when the
* browser executres events. We need to ensure we don't reactivate pointer-events within
* this timeframe otherwise the browser may execute events that should have been prevented.
*
* Additionally, this also lets us deal automatically with cancellations when a click event
* isn't raised because the page was considered scrolled/drag-scrolled, long-pressed, etc.
*
* This is why we also continuously remove the previous listener, because we cannot be
* certain that it was raised, and therefore cleaned-up.
*/ if (event.pointerType === 'touch') {
ownerDocument.removeEventListener('click', handleClickRef.current);
handleClickRef.current = handleAndDispatchPointerDownOutsideEvent;
ownerDocument.addEventListener('click', handleClickRef.current, {
once: true
});
} else handleAndDispatchPointerDownOutsideEvent();
} else // We need to remove the event listener in case the outside click has been canceled.
// See: https://github.com/radix-ui/primitives/issues/2171
ownerDocument.removeEventListener('click', handleClickRef.current);
isPointerInsideReactTreeRef.current = false;
};
/**
* if this hook executes in a component that mounts via a `pointerdown` event, the event
* would bubble up to the document and trigger a `pointerDownOutside` event. We avoid
* this by delaying the event listener registration on the document.
* This is not React specific, but rather how the DOM works, ie:
* ```
* button.addEventListener('pointerdown', () => {
* console.log('I will log');
* document.addEventListener('pointerdown', () => {
* console.log('I will also log');
* })
* });
*/ const timerId = window.setTimeout(()=>{
ownerDocument.addEventListener('pointerdown', handlePointerDown);
}, 0);
return ()=>{
window.clearTimeout(timerId);
ownerDocument.removeEventListener('pointerdown', handlePointerDown);
ownerDocument.removeEventListener('click', handleClickRef.current);
};
}, [
ownerDocument,
handlePointerDownOutside
]);
return {
// ensures we check React component tree (not just DOM tree)
onPointerDownCapture: ()=>isPointerInsideReactTreeRef.current = true
};
}
/**
* Listens for when focus happens outside a react subtree.
* Returns props to pass to the root (node) of the subtree we want to check.
*/ function $5cb92bef7577960e$var$useFocusOutside(onFocusOutside, ownerDocument = globalThis === null || globalThis === void 0 ? void 0 : globalThis.document) {
const handleFocusOutside = $b1b2314f5f9a1d84$export$25bec8c6f54ee79a(onFocusOutside);
const isFocusInsideReactTreeRef = useRef(false);
useEffect(()=>{
const handleFocus = (event)=>{
if (event.target && !isFocusInsideReactTreeRef.current) {
const eventDetail = {
originalEvent: event
};
$5cb92bef7577960e$var$handleAndDispatchCustomEvent($5cb92bef7577960e$var$FOCUS_OUTSIDE, handleFocusOutside, eventDetail, {
discrete: false
});
}
};
ownerDocument.addEventListener('focusin', handleFocus);
return ()=>ownerDocument.removeEventListener('focusin', handleFocus)
;
}, [
ownerDocument,
handleFocusOutside
]);
return {
onFocusCapture: ()=>isFocusInsideReactTreeRef.current = true
,
onBlurCapture: ()=>isFocusInsideReactTreeRef.current = false
};
}
function $5cb92bef7577960e$var$dispatchUpdate() {
const event = new CustomEvent($5cb92bef7577960e$var$CONTEXT_UPDATE);
document.dispatchEvent(event);
}
function $5cb92bef7577960e$var$handleAndDispatchCustomEvent(name, handler, detail, { discrete: discrete }) {
const target = detail.originalEvent.target;
const event = new CustomEvent(name, {
bubbles: false,
cancelable: true,
detail: detail
});
if (handler) target.addEventListener(name, handler, {
once: true
});
if (discrete) $8927f6f2acc4f386$export$6d1a0317bde7de7f(target, event);
else target.dispatchEvent(event);
}
const $d3863c46a17e8a28$var$AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';
const $d3863c46a17e8a28$var$AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';
const $d3863c46a17e8a28$var$EVENT_OPTIONS = {
bubbles: false,
cancelable: true
};
const $d3863c46a17e8a28$export$20e40289641fbbb6 = /*#__PURE__*/ forwardRef((props, forwardedRef)=>{
const { loop: loop = false , trapped: trapped = false , onMountAutoFocus: onMountAutoFocusProp , onUnmountAutoFocus: onUnmountAutoFocusProp , ...scopeProps } = props;
const [container1, setContainer] = useState(null);
const onMountAutoFocus = $b1b2314f5f9a1d84$export$25bec8c6f54ee79a(onMountAutoFocusProp);
const onUnmountAutoFocus = $b1b2314f5f9a1d84$export$25bec8c6f54ee79a(onUnmountAutoFocusProp);
const lastFocusedElementRef = useRef(null);
const composedRefs = $6ed0406888f73fc4$export$c7b2cbe3552a0d05(forwardedRef, (node)=>setContainer(node)
);
const focusScope = useRef({
paused: false,
pause () {
this.paused = true;
},
resume () {
this.paused = false;
}
}).current; // Takes care of trapping focus if focus is moved outside programmatically for example
useEffect(()=>{
if (trapped) {
function handleFocusIn(event) {
if (focusScope.paused || !container1) return;
const target = event.target;
if (container1.contains(target)) lastFocusedElementRef.current = target;
else $d3863c46a17e8a28$var$focus(lastFocusedElementRef.current, {
select: true
});
}
function handleFocusOut(event) {
if (focusScope.paused || !container1) return;
const relatedTarget = event.relatedTarget; // A `focusout` event with a `null` `relatedTarget` will happen in at least two cases:
//
// 1. When the user switches app/tabs/windows/the browser itself loses focus.
// 2. In Google Chrome, when the focused element is removed from the DOM.
//
// We let the browser do its thing here because:
//
// 1. The browser already keeps a memory of what's focused for when the page gets refocused.
// 2. In Google Chrome, if we try to focus the deleted focused element (as per below), it
// throws the CPU to 100%, so we avoid doing anything for this reason here too.
if (relatedTarget === null) return; // If the focus has moved to an actual legitimate element (`relatedTarget !== null`)
// that is outside the container, we move focus to the last valid focused element inside.
if (!container1.contains(relatedTarget)) $d3863c46a17e8a28$var$focus(lastFocusedElementRef.current, {
select: true
});
} // When the focused element gets removed from the DOM, browsers move focus
// back to the document.body. In this case, we move focus to the container
// to keep focus trapped correctly.
function handleMutations(mutations) {
const focusedElement = document.activeElement;
if (focusedElement !== document.body) return;
for (const mutation of mutations)if (mutation.removedNodes.length > 0) $d3863c46a17e8a28$var$focus(container1);
}
document.addEventListener('focusin', handleFocusIn);
document.addEventListener('focusout', handleFocusOut);
const mutationObserver = new MutationObserver(handleMutations);
if (container1) mutationObserver.observe(container1, {
childList: true,
subtree: true
});
return ()=>{
document.removeEventListener('focusin', handleFocusIn);
document.removeEventListener('focusout', handleFocusOut);
mutationObserver.disconnect();
};
}
}, [
trapped,
container1,
focusScope.paused
]);
useEffect(()=>{
if (container1) {
$d3863c46a17e8a28$var$focusScopesStack.add(focusScope);
const previouslyFocusedElement = document.activeElement;
const hasFocusedCandidate = container1.contains(previouslyFocusedElement);
if (!hasFocusedCandidate) {
const mountEvent = new CustomEvent($d3863c46a17e8a28$var$AUTOFOCUS_ON_MOUNT, $d3863c46a17e8a28$var$EVENT_OPTIONS);
container1.addEventListener($d3863c46a17e8a28$var$AUTOFOCUS_ON_MOUNT, onMountAutoFocus);
container1.dispatchEvent(mountEvent);
if (!mountEvent.defaultPrevented) {
$d3863c46a17e8a28$var$focusFirst($d3863c46a17e8a28$var$removeLinks($d3863c46a17e8a28$var$getTabbableCandidates(container1)), {
select: true
});
if (document.activeElement === previouslyFocusedElement) $d3863c46a17e8a28$var$focus(container1);
}
}
return ()=>{
container1.removeEventListener($d3863c46a17e8a28$var$AUTOFOCUS_ON_MOUNT, onMountAutoFocus); // We hit a react bug (fixed in v17) with focusing in unmount.
// We need to delay the focus a little to get around it for now.
// See: https://github.com/facebook/react/issues/17894
setTimeout(()=>{
const unmountEvent = new CustomEvent($d3863c46a17e8a28$var$AUTOFOCUS_ON_UNMOUNT, $d3863c46a17e8a28$var$EVENT_OPTIONS);
container1.addEventListener($d3863c46a17e8a28$var$AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
container1.dispatchEvent(unmountEvent);
if (!unmountEvent.defaultPrevented) $d3863c46a17e8a28$var$focus(previouslyFocusedElement !== null && previouslyFocusedElement !== void 0 ? previouslyFocusedElement : document.body, {
select: true
});
// we need to remove the listener after we `dispatchEvent`
container1.removeEventListener($d3863c46a17e8a28$var$AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);
$d3863c46a17e8a28$var$focusScopesStack.remove(focusScope);
}, 0);
};
}
}, [
container1,
onMountAutoFocus,
onUnmountAutoFocus,
focusScope
]); // Takes care of looping focus (when tabbing whilst at the edges)
const handleKeyDown = useCallback((event)=>{
if (!loop && !trapped) return;
if (focusScope.paused) return;
const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;
const focusedElement = document.activeElement;
if (isTabKey && focusedElement) {
const container = event.currentTarget;
const [first, last] = $d3863c46a17e8a28$var$getTabbableEdges(container);
const hasTabbableElementsInside = first && last; // we can only wrap focus if we have tabbable edges
if (!hasTabbableElementsInside) {
if (focusedElement === container) event.preventDefault();
} else {
if (!event.shiftKey && focusedElement === last) {
event.preventDefault();
if (loop) $d3863c46a17e8a28$var$focus(first, {
select: true
});
} else if (event.shiftKey && focusedElement === first) {
event.preventDefault();
if (loop) $d3863c46a17e8a28$var$focus(last, {
select: true
});
}
}
}
}, [
loop,
trapped,
focusScope.paused
]);
return /*#__PURE__*/ createElement($8927f6f2acc4f386$export$250ffa63cdc0d034.div, _extends({
tabIndex: -1
}, scopeProps, {
ref: composedRefs,
onKeyDown: handleKeyDown
}));
});
/* -------------------------------------------------------------------------------------------------
* Utils
* -----------------------------------------------------------------------------------------------*/ /**
* Attempts focusing the first element in a list of candidates.
* Stops when focus has actually moved.
*/ function $d3863c46a17e8a28$var$focusFirst(candidates, { select: select = false } = {}) {
const previouslyFocusedElement = document.activeElement;
for (const candidate of candidates){
$d3863c46a17e8a28$var$focus(candidate, {
select: select
});
if (document.activeElement !== previouslyFocusedElement) return;
}
}
/**
* Returns the first and last tabbable elements inside a container.
*/ function $d3863c46a17e8a28$var$getTabbableEdges(container) {
const candidates = $d3863c46a17e8a28$var$getTabbableCandidates(container);
const first = $d3863c46a17e8a28$var$findVisible(candidates, container);
const last = $d3863c46a17e8a28$var$findVisible(candidates.reverse(), container);
return [
first,
last
];
}
/**
* Returns a list of potential tabbable candidates.
*
* NOTE: This is only a close approximation. For example it doesn't take into account cases like when
* elements are not visible. This cannot be worked out easily by just reading a property, but rather
* necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.
*
* See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker
* Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1
*/ function $d3863c46a17e8a28$var$getTabbableCandidates(container) {
const nodes = [];
const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
acceptNode: (node)=>{
const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';
if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP; // `.tabIndex` is not the same as the `tabindex` attribute. It works on the
// runtime's understanding of tabbability, so this automatically accounts
// for any kind of element that could be tabbed to.
return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
}
});
while(walker.nextNode())nodes.push(walker.currentNode); // we do not take into account the order of nodes with positive `tabIndex` as it
// hinders accessibility to have tab order different from visual order.
return nodes;
}
/**
* Returns the first visible element in a list.
* NOTE: Only checks visibility up to the `container`.
*/ function $d3863c46a17e8a28$var$findVisible(elements, container) {
for (const element of elements){
// we stop checking if it's hidden at the `container` level (excluding)
if (!$d3863c46a17e8a28$var$isHidden(element, {
upTo: container
})) return element;
}
}
function $d3863c46a17e8a28$var$isHidden(node, { upTo: upTo }) {
if (getComputedStyle(node).visibility === 'hidden') return true;
while(node){
// we stop at `upTo` (excluding it)
if (upTo !== undefined && node === upTo) return false;
if (getComputedStyle(node).display === 'none') return true;
node = node.parentElement;
}
return false;
}
function $d3863c46a17e8a28$var$isSelectableInput(element) {
return element instanceof HTMLInputElement && 'select' in element;
}
function $d3863c46a17e8a28$var$focus(element, { select: select = false } = {}) {
// only focus if that element is focusable
if (element && element.focus) {
const previouslyFocusedElement = document.activeElement; // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users
element.focus({
preventScroll: true
}); // only select if its not the same element, it supports selection and we need to select
if (element !== previouslyFocusedElement && $d3863c46a17e8a28$var$isSelectableInput(element) && select) element.select();
}
}
/* -------------------------------------------------------------------------------------------------
* FocusScope stack
* -----------------------------------------------------------------------------------------------*/ const $d3863c46a17e8a28$var$focusScopesStack = $d3863c46a17e8a28$var$createFocusScopesStack();
function $d3863c46a17e8a28$var$createFocusScopesStack() {
/** A stack of focus scopes, with the active one at the top */ let stack = [];
return {
add (focusScope) {
// pause the currently active focus scope (at the top of the stack)
const activeFocusScope = stack[0];
if (focusScope !== activeFocusScope) activeFocusScope === null || activeFocusScope === void 0 || activeFocusScope.pause();
// remove in case it already exists (because we'll re-add it at the top of the stack)
stack = $d3863c46a17e8a28$var$arrayRemove(stack, focusScope);
stack.unshift(focusScope);
},
remove (focusScope) {
var _stack$;
stack = $d3863c46a17e8a28$var$arrayRemove(stack, focusScope);
(_stack$ = stack[0]) === null || _stack$ === void 0 || _stack$.resume();
}
};
}
function $d3863c46a17e8a28$var$arrayRemove(array, item) {
const updatedArray = [
...array
];
const index = updatedArray.indexOf(item);
if (index !== -1) updatedArray.splice(index, 1);
return updatedArray;
}
function $d3863c46a17e8a28$var$removeLinks(items) {
return items.filter((item)=>item.tagName !== 'A'
);
}
const $f1701beae083dbae$export$602eac185826482c = /*#__PURE__*/ forwardRef((props, forwardedRef)=>{
var _globalThis$document;
const { container: container = globalThis === null || globalThis === void 0 ? void 0 : (_globalThis$document = globalThis.document) === null || _globalThis$document === void 0 ? void 0 : _globalThis$document.body , ...portalProps } = props;
return container ? /*#__PURE__*/ $7SXl2$reactdom.createPortal(/*#__PURE__*/ createElement($8927f6f2acc4f386$export$250ffa63cdc0d034.div, _extends({}, portalProps, {
ref: forwardedRef
})), container) : null;
});
function $fe963b355347cc68$export$3e6543de14f8614f(initialState, machine) {
return useReducer((state, event)=>{
const nextState = machine[state][event];
return nextState !== null && nextState !== void 0 ? nextState : state;
}, initialState);
}
const $921a889cee6df7e8$export$99c2b779aa4e8b8b = (props)=>{
const { present: present , children: children } = props;
const presence = $921a889cee6df7e8$var$usePresence(present);
const child = typeof children === 'function' ? children({
present: presence.isPresent
}) : Children.only(children);
const ref = $6ed0406888f73fc4$export$c7b2cbe3552a0d05(presence.ref, child.ref);
const forceMount = typeof children === 'function';
return forceMount || presence.isPresent ? /*#__PURE__*/ cloneElement(child, {
ref: ref
}) : null;
};
$921a889cee6df7e8$export$99c2b779aa4e8b8b.displayName = 'Presence';
/* -------------------------------------------------------------------------------------------------
* usePresence
* -----------------------------------------------------------------------------------------------*/ function $921a889cee6df7e8$var$usePresence(present) {
const [node1, setNode] = useState();
const stylesRef = useRef({});
const prevPresentRef = useRef(present);
const prevAnimationNameRef = useRef('none');
const initialState = present ? 'mounted' : 'unmounted';
const [state, send] = $fe963b355347cc68$export$3e6543de14f8614f(initialState, {
mounted: {
UNMOUNT: 'unmounted',
ANIMATION_OUT: 'unmountSuspended'
},
unmountSuspended: {
MOUNT: 'mounted',
ANIMATION_END: 'unmounted'
},
unmounted: {
MOUNT: 'mounted'
}
});
useEffect(()=>{
const currentAnimationName = $921a889cee6df7e8$var$getAnimationName(stylesRef.current);
prevAnimationNameRef.current = state === 'mounted' ? currentAnimationName : 'none';
}, [
state
]);
$9f79659886946c16$export$e5c5a5f917a5871c(()=>{
const styles = stylesRef.current;
const wasPresent = prevPresentRef.current;
const hasPresentChanged = wasPresent !== present;
if (hasPresentChanged) {
const prevAnimationName = prevAnimationNameRef.current;
const currentAnimationName = $921a889cee6df7e8$var$getAnimationName(styles);
if (present) send('MOUNT');
else if (currentAnimationName === 'none' || (styles === null || styles === void 0 ? void 0 : styles.display) === 'none') // If there is no exit animation or the element is hidden, animations won't run
// so we unmount instantly
send('UNMOUNT');
else {
/**
* When `present` changes to `false`, we check changes to animation-name to
* determine whether an animation has started. We chose this approach (reading
* computed styles) because there is no `animationrun` event and `animationstart`
* fires after `animation-delay` has expired which would be too late.
*/ const isAnimating = prevAnimationName !== currentAnimationName;
if (wasPresent && isAnimating) send('ANIMATION_OUT');
else send('UNMOUNT');
}
prevPresentRef.current = present;
}
}, [
present,
send
]);
$9f79659886946c16$export$e5c5a5f917a5871c(()=>{
if (node1) {
/**
* Triggering an ANIMATION_OUT during an ANIMATION_IN will fire an `animationcancel`
* event for ANIMATION_IN after we have entered `unmountSuspended` state. So, we
* make sure we only trigger ANIMATION_END for the currently active animation.
*/ const handleAnimationEnd = (event)=>{
const currentAnimationName = $921a889cee6df7e8$var$getAnimationName(stylesRef.current);
const isCurrentAnimation = currentAnimationName.includes(event.animationName);
if (event.target === node1 && isCurrentAnimation) // With React 18 concurrency this update is applied
// a frame after the animation ends, creating a flash of visible content.
// By manually flushing we ensure they sync within a frame, removing the flash.
flushSync(()=>send('ANIMATION_END')
);
};
const handleAnimationStart = (event)=>{
if (event.target === node1) // if animation occurred, store its name as the previous animation.
prevAnimationNameRef.current = $921a889cee6df7e8$var$getAnimationName(stylesRef.current);
};
node1.addEventListener('animationstart', handleAnimationStart);
node1.addEventListener('animationcancel', handleAnimationEnd);
node1.addEventListener('animationend', handleAnimationEnd);
return ()=>{
node1.removeEventListener('animationstart', handleAnimationStart);
node1.removeEventListener('animationcancel', handleAnimationEnd);
node1.removeEventListener('animationend', handleAnimationEnd);
};
} else // Transition to the unmounted state if the node is removed prematurely.
// We avoid doing so during cleanup as the node may change but still exist.
send('ANIMATION_END');
}, [
node1,
send
]);
return {
isPresent: [
'mounted',
'unmountSuspended'
].includes(state),
ref: useCallback((node)=>{
if (node) stylesRef.current = getComputedStyle(node);
setNode(node);
}, [])
};
}
/* -----------------------------------------------------------------------------------------------*/ function $921a889cee6df7e8$var$getAnimationName(styles) {
return (styles === null || styles === void 0 ? void 0 : styles.animationName) || 'none';
}
/** Number of components which have requested interest to have focus guards */ let $3db38b7d1fb3fe6a$var$count = 0;
/**
* Injects a pair of focus guards at the edges of the whole DOM tree
* to ensure `focusin` & `focusout` events can be caught consistently.
*/ function $3db38b7d1fb3fe6a$export$b7ece24a22aeda8c() {
useEffect(()=>{
var _edgeGuards$, _edgeGuards$2;
const edgeGuards = document.querySelectorAll('[data-radix-focus-guard]');
document.body.insertAdjacentElement('afterbegin', (_edgeGuards$ = edgeGuards[0]) !== null && _edgeGuards$ !== void 0 ? _edgeGuards$ : $3db38b7d1fb3fe6a$var$createFocusGuard());
document.body.insertAdjacentElement('beforeend', (_edgeGuards$2 = edgeGuards[1]) !== null && _edgeGuards$2 !== void 0 ? _edgeGuards$2 : $3db38b7d1fb3fe6a$var$createFocusGuard());
$3db38b7d1fb3fe6a$var$count++;
return ()=>{
if ($3db38b7d1fb3fe6a$var$count === 1) document.querySelectorAll('[data-radix-focus-guard]').forEach((node)=>node.remove()
);
$3db38b7d1fb3fe6a$var$count--;
};
}, []);
}
function $3db38b7d1fb3fe6a$var$createFocusGuard() {
const element = document.createElement('span');
element.setAttribute('data-radix-focus-guard', '');
element.tabIndex = 0;
element.style.cssText = 'outline: none; opacity: 0; position: fixed; pointer-events: none';
return element;
}
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __rest(s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
function __spreadArray(to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
var zeroRightClassName = 'right-scroll-bar-position';
var fullWidthClassName = 'width-before-scroll-bar';
var noScrollbarsClassName = 'with-scroll-bars-hidden';
/**
* Name of a CSS variable containing the amount of "hidden" scrollbar
* ! might be undefined ! use will fallback!
*/
var removedBarSizeVariable = '--removed-body-scroll-bar-size';
/**
* Assigns a value for a given ref, no matter of the ref format
* @param {RefObject} ref - a callback function or ref object
* @param value - a new value
*
* @see https://github.com/theKashey/use-callback-ref#assignref
* @example
* const refObject = useRef();
* const refFn = (ref) => {....}
*
* assignRef(refObject, "refValue");
* assignRef(refFn, "refValue");
*/
function assignRef(ref, value) {
if (typeof ref === 'function') {
ref(value);
}
else if (ref) {
ref.current = value;
}
return ref;
}
/**
* creates a MutableRef with ref change callback
* @param initialValue - initial ref value
* @param {Function} callback - a callback to run when value changes
*
* @example
* const ref = useCallbackRef(0, (newValue, oldValue) => console.log(oldValue, '->', newValue);
* ref.current = 1;
* // prints 0 -> 1
*
* @see https://reactjs.org/docs/hooks-reference.html#useref
* @see https://github.com/theKashey/use-callback-ref#usecallbackref---to-replace-reactuseref
* @returns {MutableRefObject}
*/
function useCallbackRef(initialValue, callback) {
var ref = useState(function () { return ({
// value
value: initialValue,
// last callback
callback: callback,
// "memoized" public interface
facade: {
get current() {
return ref.value;
},
set current(value) {
var last = ref.value;
if (last !== value) {
ref.value = value;
ref.callback(value, last);
}
},
},
}); })[0];
// update callback
ref.callback = callback;
return ref.facade;
}
var currentValues = new WeakMap();
/**
* Merges two or more refs together providing a single interface to set their value
* @param {RefObject|Ref} refs
* @returns {MutableRefObject} - a new ref, which translates all changes to {refs}
*
* @see {@link mergeRefs} a version without buit-in memoization
* @see https://github.com/theKashey/use-callback-ref#usemergerefs
* @example
* const Component = React.forwardRef((props, ref) => {
* const ownRef = useRef();
* const domRef = useMergeRefs([ref, ownRef]); // 👈 merge together
* return <div ref={domRef}>...</div>
* }
*/
function useMergeRefs(refs, defaultValue) {
var callbackRef = useCallbackRef(defaultValue || null, function (newValue) {
return refs.forEach(function (ref) { return assignRef(ref, newValue); });
});
// handle refs changes - added or removed
React.useLayoutEffect(function () {
var oldValue = currentValues.get(callbackRef);
if (oldValue) {
var prevRefs_1 = new Set(oldValue);
var nextRefs_1 = new Set(refs);
var current_1 = callbackRef.current;
prevRefs_1.forEach(function (ref) {
if (!nextRefs_1.has(ref)) {
assignRef(ref, null);
}
});
nextRefs_1.forEach(function (ref) {
if (!prevRefs_1.has(ref)) {
assignRef(ref, current_1);
}
});
}
currentValues.set(callbackRef, refs);
}, [refs]);
return callbackRef;
}
function ItoI(a) {
return a;
}
function innerCreateMedium(defaults, middleware) {
if (middleware === void 0) { middleware = ItoI; }
var buffer = [];
var assigned = false;
var medium = {
read: function () {
if (assigned) {
throw new Error('Sidecar: could not `read` from an `assigned` medium. `read` could be used only with `useMedium`.');
}
if (buffer.length) {
return buffer[buffer.length - 1];
}
return defaults;
},
useMedium: function (data) {
var item = middleware(data, assigned);
buffer.push(item);
return function () {
buffer = buffer.filter(function (x) { return x !== item; });
};
},
assignSyncMedium: function (cb) {
assigned = true;
while (buffer.length) {
var cbs = buffer;
buffer = [];
cbs.forEach(cb);
}
buffer = {
push: function (x) { return cb(x); },
filter: function () { return buffer; },
};
},
assignMedium: function (cb) {
assigned = true;
var pendingQueue = [];
if (buffer.length) {
var cbs = buffer;
buffer = [];
cbs.forEach(cb);
pendingQueue = buffer;
}
var executeQueue = function () {
var cbs = pendingQueue;
pendingQueue = [];
cbs.forEach(cb);
};
var cycle = function () { return Promise.resolve().then(executeQueue); };
cycle();
buffer = {
push: function (x) {
pendingQueue.push(x);
cycle();
},
filter: function (filter) {
pendingQueue = pendingQueue.filter(filter);
return buffer;
},
};
},
};
return medium;
}
// eslint-disable-next-line @typescript-eslint/ban-types
function createSidecarMedium(options) {
if (options === void 0) { options = {}; }
var medium = innerCreateMedium(null);
medium.options = __assign({ async: true, ssr: false }, options);
return medium;
}
var SideCar$1 = function (_a) {
var sideCar = _a.sideCar, rest = __rest(_a, ["sideCar"]);
if (!sideCar) {
throw new Error('Sidecar: please provide `sideCar` property to import the right car');
}
var Target = sideCar.read();
if (!Target) {
throw new Error('Sidecar medium not found');
}
return React.createElement(Target, __assign({}, rest));
};
SideCar$1.isSideCarExport = true;
function exportSidecar(medium, exported) {
medium.useMedium(exported);
return SideCar$1;
}
var effectCar = createSidecarMedium();
var nothing = function () {
return;
};
/**
* Removes scrollbar from the page and contain the scroll within the Lock
*/
var RemoveScroll = React.forwardRef(function (props, parentRef) {
var ref = React.useRef(null);
var _a = React.useState({
onScrollCapture: nothing,
onWheelCapture: nothing,
onTouchMoveCapture: nothing,
}), callbacks = _a[0], setCallbacks = _a[1];
var forwardProps = props.forwardProps, children = props.children, className = props.className, removeScrollBar = props.removeScrollBar, enabled = props.enabled, shards = props.shards, sideCar = props.sideCar, noIsolation = props.noIsolation, inert = props.inert, allowPinchZoom = props.allowPinchZoom, _b = props.as, Container = _b === void 0 ? 'div' : _b, rest = __rest(props, ["forwardProps", "children", "className", "removeScrollBar", "enabled", "shards", "sideCar", "noIsolation", "inert", "allowPinchZoom", "as"]);
var SideCar = sideCar;
var containerRef = useMergeRefs([ref, parentRef]);
var containerProps = __assign(__assign({}, rest), callbacks);
return (React.createElement(React.Fragment, null,
enabled && (React.createElement(SideCar, { sideCar: effectCar, removeScrollBar: removeScrollBar, shards: shards, noIsolation: noIsolation, inert: inert, setCallbacks: setCallbacks, allowPinchZoom: !!allowPinchZoom, lockRef: ref })),
forwardProps ? (React.cloneElement(React.Children.only(children), __assign(__assign({}, containerProps), { ref: containerRef }))) : (React.createElement(Container, __assign({}, containerProps, { className: className, ref: containerRef }), children))));
});
RemoveScroll.defaultProps = {
enabled: true,
removeScrollBar: true,
inert: false,
};
RemoveScroll.classNames = {
fullWidth: fullWidthClassName,
zeroRight: zeroRightClassName,
};
var currentNonce;
var getNonce = function () {
if (currentNonce) {
return currentNonce;
}
if (typeof __webpack_nonce__ !== 'undefined') {
return __webpack_nonce__;
}
return undefined;
};
function makeStyleTag() {
if (!document)
return null;
var tag = document.createElement('style');
tag.type = 'text/css';
var nonce = getNonce();
if (nonce) {
tag.setAttribute('nonce', nonce);
}
return tag;
}
function injectStyles(tag, css) {
// @ts-ignore
if (tag.styleSheet) {
// @ts-ignore
tag.styleSheet.cssText = css;
}
else {
tag.appendChild(document.createTextNode(css));
}
}
function insertStyleTag(tag) {
var head = document.head || document.getElementsByTagName('head')[0];
head.appendChild(tag);
}
var stylesheetSingleton = function () {
var counter = 0;
var stylesheet = null;
return {
add: function (style) {
if (counter == 0) {
if ((stylesheet = makeStyleTag())) {
injectStyles(stylesheet, style);
insertStyleTag(stylesheet);
}
}
counter++;
},
remove: function () {
counter--;
if (!counter && stylesheet) {
stylesheet.parentNode && stylesheet.parentNode.removeChild(stylesheet);
stylesheet = null;
}
},
};
};
/**
* creates a hook to control style singleton
* @see {@link styleSingleton} for a safer component version
* @example
* ```tsx
* const useStyle = styleHookSingleton();
* ///
* useStyle('body { overflow: hidden}');
*/
var styleHookSingleton = function () {
var sheet = stylesheetSingleton();
return function (styles, isDynamic) {
React.useEffect(function () {
sheet.add(styles);
return function () {
sheet.remove();
};
}, [styles && isDynamic]);
};
};
/**
* create a Component to add styles on demand
* - styles are added when first instance is mounted
* - styles are removed when the last instance is unmounted
* - changing styles in runtime does nothing unless dynamic is set. But with multiple components that can lead to the undefined behavior
*/
var styleSingleton = function () {
var useStyle = styleHookSingleton();
var Sheet = function (_a) {
var styles = _a.styles, dynamic = _a.dynamic;
useStyle(styles, dynamic);
return null;
};
return Sheet;
};
var zeroGap = {
left: 0,
top: 0,
right: 0,
gap: 0,
};
var parse = function (x) { return parseInt(x || '', 10) || 0; };
var getOffset = function (gapMode) {
var cs = window.getComputedStyle(document.body);
var left = cs[gapMode === 'padding' ? 'paddingLeft' : 'marginLeft'];
var top = cs[gapMode === 'padding' ? 'paddingTop' : 'marginTop'];
var right = cs[gapMode === 'padding' ? 'paddingRight' : 'marginRight'];
return [parse(left), parse(top), parse(right)];
};
var getGapWidth = function (gapMode) {
if (gapMode === void 0) { gapMode = 'margin'; }
if (typeof window === 'undefined') {
return zeroGap;
}
var offsets = getOffset(gapMode);
var documentWidth = document.documentElement.clientWidth;
var windowWidth = window.innerWidth;
return {
left: offsets[0],
top: offsets[1],
right: offsets[2],
gap: Math.max(0, windowWidth - documentWidth + offsets[2] - offsets[0]),
};
};
var Style = styleSingleton();
// important tip - once we measure scrollBar width and remove them
// we could not repeat this operation
// thus we are using style-singleton - only the first "yet correct" style will be applied.
var getStyles = function (_a, allowRelative, gapMode, important) {
var left = _a.left, top = _a.top, right = _a.right, gap = _a.gap;
if (gapMode === void 0) { gapMode = 'margin'; }
return "\n .".concat(noScrollbarsClassName, " {\n overflow: hidden ").concat(important, ";\n padding-right: ").concat(gap, "px ").concat(important, ";\n }\n body {\n overflow: hidden ").concat(important, ";\n overscroll-behavior: contain;\n ").concat([
allowRelative && "position: relative ".concat(important, ";"),
gapMode === 'margin' &&
"\n padding-left: ".concat(left, "px;\n padding-top: ").concat(top, "px;\n padding-right: ").concat(right, "px;\n margin-left:0;\n margin-top:0;\n margin-right: ").concat(gap, "px ").concat(important, ";\n "),
gapMode === 'padding' && "padding-right: ".concat(gap, "px ").concat(important, ";"),
]
.filter(Boolean)
.join(''), "\n }\n \n .").concat(zeroRightClassName, " {\n right: ").concat(gap, "px ").concat(important, ";\n }\n \n .").concat(fullWidthClassName, " {\n margin-right: ").concat(gap, "px ").concat(important, ";\n }\n \n .").concat(zeroRightClassName, " .").concat(zeroRightClassName, " {\n right: 0 ").concat(important, ";\n }\n \n .").concat(fullWidthClassName, " .").concat(fullWidthClassName, " {\n margin-right: 0 ").concat(important, ";\n }\n \n body {\n ").concat(removedBarSizeVariable, ": ").concat(gap, "px;\n }\n");
};
/**
* Removes page scrollbar and blocks page scroll when mounted
*/
var RemoveScrollBar = function (props) {
var noRelative = props.noRelative, noImportant = props.noImportant, _a = props.gapMode, gapMode = _a === void 0 ? 'margin' : _a;
/*
gap will be measured on every component mount
however it will be used only by the "first" invocation
due to singleton nature of <Style
*/
var gap = React.useMemo(function () { return getGapWidth(gapMode); }, [gapMode]);
return React.createElement(Style, { styles: getStyles(gap, !noRelative, gapMode, !noImportant ? '!important' : '') });
};
var passiveSupported = false;
if (typeof window !== 'undefined') {
try {
var options = Object.defineProperty({}, 'passive', {
get: function () {
passiveSupported = true;
return true;
},
});
// @ts-ignore
window.addEventListener('test', options, options);
// @ts-ignore
window.removeEventListener('test', options, options);
}
catch (err) {
passiveSupported = false;
}
}
var nonPassive = passiveSupported ? { passive: false } : false;
var alwaysContainsScroll = function (node) {
// textarea will always _contain_ scroll inside self. It only can be hidden
return node.tagName === 'TEXTAREA';
};
var elementCanBeScrolled = function (node, overflow) {
var styles = window.getComputedStyle(node);
return (
// not-not-scrollable
styles[overflow] !== 'hidden' &&
// contains scroll inside self
!(styles.overflowY === styles.overflowX && !alwaysContainsScroll(node) && styles[overflow] === 'visible'));
};
var elementCouldBeVScrolled = function (node) { return elementCanBeScrolled(node, 'overflowY'); };
var elementCouldBeHScrolled = function (node) { return elementCanBeScrolled(node, 'overflowX'); };
var locationCouldBeScrolled = function (axis, node) {
var current = node;
do {
// Skip over shadow root
if (typeof ShadowRoot !== 'undefined' && current instanceof ShadowRoot) {
current = current.host;
}
var isScrollable = elementCouldBeScrolled(axis, current);
if (isScrollable) {
var _a = getScrollVariables(axis, current), s = _a[1], d = _a[2];
if (s > d) {
return true;
}
}
current = current.parentNode;
} while (current && current !== document.body);
return false;
};
var getVScrollVariables = function (_a) {
var scrollTop = _a.scrollTop, scrollHeight = _a.scrollHeight, clientHeight = _a.clientHeight;
return [
scrollTop,
scrollHeight,
clientHeight,
];
};
var getHScrollVariables = function (_a) {
var scrollLeft = _a.scrollLeft, scrollWidth = _a.scrollWidth, clientWidth = _a.clientWidth;
return [
scrollLeft,
scrollWidth,
clientWidth,
];
};
var elementCouldBeScrolled = function (axis, node) {
return axis === 'v' ? elementCouldBeVScrolled(node) : elementCouldBeHScrolled(node);
};
var getScrollVariables = function (axis, node) {
return axis === 'v' ? getVScrollVariables(node) : getHScrollVariables(node);
};
var getDirectionFactor = function (axis, direction) {
/**
* If the element's direction is rtl (right-to-left), then scrollLeft is 0 when the scrollbar is at its rightmost position,
* and then increasingly negative as you scroll towards the end of the content.
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
*/
return axis === 'h' && direction === 'rtl' ? -1 : 1;
};
var handleScroll = function (axis, endTarget, event, sourceDelta, noOverscroll) {
var directionFactor = getDirectionFactor(axis, window.getComputedStyle(endTarget).direction);
var delta = directionFactor * sourceDelta;
// find scrollable target
var target = event.target;
var targetInLock = endTarget.contains(target);
var shouldCancelScroll = false;
var isDeltaPositive = delta > 0;
var availableScroll = 0;
var availableScrollTop = 0;
do {
var _a = getScrollVariables(axis, target), position = _a[0], scroll_1 = _a[1], capacity = _a[2];
var elementScroll = scroll_1 - capacity - directionFactor * position;
if (position || elementScroll) {
if (elementCouldBeScrolled(axis, target)) {
availableScroll += elementScroll;
availableScrollTop += position;
}
}
target = target.parentNode;
} while (
// portaled content
(!targetInLock && target !== document.body) ||
// self content
(targetInLock && (endTarget.contains(target) || endTarget === target)));
if (isDeltaPositive && ((noOverscroll && availableScroll === 0) || (!noOverscroll && delta > availableScroll))) {
shouldCancelScroll = true;
}
else if (!isDeltaPositive &&
((noOverscroll && availableScrollTop === 0) || (!noOverscroll && -delta > availableScrollTop))) {
shouldCancelScroll = true;
}
return shouldCancelScroll;
};
var getTouchXY = function (event) {
return 'changedTouches' in event ? [event.changedTouches[0].clientX, event.changedTouches[0].clientY] : [0, 0];
};
var getDeltaXY = function (event) { return [event.deltaX, event.deltaY]; };
var extractRef = function (ref) {
return ref && 'current' in ref ? ref.current : ref;
};
var deltaCompare = function (x, y) { return x[0] === y[0] && x[1] === y[1]; };
var generateStyle = function (id) { return "\n .block-interactivity-".concat(id, " {pointer-events: none;}\n .allow-interactivity-").concat(id, " {pointer-events: all;}\n"); };
var idCounter = 0;
var lockStack = [];
function RemoveScrollSideCar(props) {
var shouldPreventQueue = React.useRef([]);
var touchStartRef = React.useRef([0, 0]);
var activeAxis = React.useRef();
var id = React.useState(idCounter++)[0];
var Style = React.useState(function () { return styleSingleton(); })[0];
var lastProps = React.useRef(props);
React.useEffect(function () {
lastProps.current = props;
}, [props]);
React.useEffect(function () {
if (props.inert) {
document.body.classList.add("block-interactivity-".concat(id));
var allow_1 = __spreadArray([props.lockRef.current], (props.shards || []).map(extractRef), true).filter(Boolean);
allow_1.forEach(function (el) { return el.classList.add("allow-interactivity-".concat(id)); });
return function () {
document.body.classList.remove("block-interactivity-".concat(id));
allow_1.forEach(function (el) { return el.classList.remove("allow-interactivity-".concat(id)); });
};
}
return;
}, [props.inert, props.lockRef.current, props.shards]);
var shouldCancelEvent = React.useCallback(function (event, parent) {
if ('touches' in event && event.touches.length === 2) {
return !lastProps.current.allowPinchZoom;
}
var touch = getTouchXY(event);
var touchStart = touchStartRef.current;
var deltaX = 'deltaX' in event ? event.deltaX : touchStart[0] - touch[0];
var deltaY = 'deltaY' in event ? event.deltaY : touchStart[1] - touch[1];
var currentAxis;
var target = event.target;
var moveDirection = Math.abs(deltaX) > Math.abs(deltaY) ? 'h' : 'v';
// allow horizontal touch move on Range inputs. They will not cause any scroll
if ('touches' in event && moveDirection === 'h' && target.type === 'range') {
return false;
}
var canBeScrolledInMainDirection = locationCouldBeScrolled(moveDirection, target);
if (!canBeScrolledInMainDirection) {
return true;
}
if (canBeScrolledInMainDirection) {
currentAxis = moveDirection;
}
else {
currentAxis = moveDirection === 'v' ? 'h' : 'v';
canBeScrolledInMainDirection = locationCouldBeScrolled(moveDirection, target);
// other axis might be not scrollable
}
if (!canBeScrolledInMainDirection) {
return false;
}
if (!activeAxis.current && 'changedTouches' in event && (deltaX || deltaY)) {
activeAxis.current = currentAxis;
}
if (!currentAxis) {
return true;
}
var cancelingAxis = activeAxis.current || currentAxis;
return handleScroll(cancelingAxis, parent, event, cancelingAxis === 'h' ? deltaX : deltaY, true);
}, []);
var shouldPrevent = React.useCallback(function (_event) {
var event = _event;
if (!lockStack.length || lockStack[lockStack.length - 1] !== Style) {
// not the last active
return;
}
var delta = 'deltaY' in event ? getDeltaXY(event) : getTouchXY(event);
var sourceEvent = shouldPreventQueue.current.filter(function (e) { return e.name === event.type && e.target === event.target && deltaCompare(e.delta, delta); })[0];
// self event, and should be canceled
if (sourceEvent && sourceEvent.should) {
if (event.cancelable) {
event.preventDefault();
}
return;
}
// outside or shard event
if (!sourceEvent) {
var shardNodes = (lastProps.current.shards || [])
.map(extractRef)
.filter(Boolean)
.filter(function (node) { return node.contains(event.target); });
var shouldStop = shardNodes.length > 0 ? shouldCancelEvent(event, shardNodes[0]) : !lastProps.current.noIsolation;
if (shouldStop) {
if (event.cancelable) {
event.preventDefault();
}
}
}
}, []);
var shouldCancel = React.useCallback(function (name, delta, target, should) {
var event = { name: name, delta: delta, target: target, should: should };
shouldPreventQueue.current.push(event);
setTimeout(function () {
shouldPreventQueue.current = shouldPreventQueue.current.filter(function (e) { return e !== event; });
}, 1);
}, []);
var scrollTouchStart = React.useCallback(function (event) {
touchStartRef.current = getTouchXY(event);
activeAxis.current = undefined;
}, []);
var scrollWheel = React.useCallback(function (event) {
shouldCancel(event.type, getDeltaXY(event), event.target, shouldCancelEvent(event, props.lockRef.current));
}, []);
var scrollTouchMove = React.useCallback(function (event) {
shouldCancel(event.type, getTouchXY(event), event.target, shouldCancelEvent(event, props.lockRef.current));
}, []);
React.useEffect(function () {
lockStack.push(Style);
props.setCallbacks({
onScrollCapture: scrollWheel,
onWheelCapture: scrollWheel,
onTouchMoveCapture: scrollTouchMove,
});
document.addEventListener('wheel', shouldPrevent, nonPassive);
document.addEventListener('touchmove', shouldPrevent, nonPassive);
document.addEventListener('touchstart', scrollTouchStart, nonPassive);
return function () {
lockStack = lockStack.filter(function (inst) { return inst !== Style; });
document.removeEventListener('wheel', shouldPrevent, nonPassive);
document.removeEventListener('touchmove', shouldPrevent, nonPassive);
document.removeEventListener('touchstart', scrollTouchStart, nonPassive);
};
}, []);
var removeScrollBar = props.removeScrollBar, inert = props.inert;
return (React.createElement(React.Fragment, null,
inert ? React.createElement(Style, { styles: generateStyle(id) }) : null,
removeScrollBar ? React.createElement(RemoveScrollBar, { gapMode: "margin" }) : null));
}
var SideCar = exportSidecar(effectCar, RemoveScrollSideCar);
var ReactRemoveScroll = React.forwardRef(function (props, ref) { return (React.createElement(RemoveScroll, __assign({}, props, { ref: ref, sideCar: SideCar }))); });
ReactRemoveScroll.classNames = RemoveScroll.classNames;
var $67UHm$RemoveScroll = ReactRemoveScroll;
var getDefaultParent = function (originalTarget) {
if (typeof document === 'undefined') {
return null;
}
var sampleTarget = Array.isArray(originalTarget) ? originalTarget[0] : originalTarget;
return sampleTarget.ownerDocument.body;
};
var counterMap = new WeakMap();
var uncontrolledNodes = new WeakMap();
var markerMap = {};
var lockCount = 0;
var unwrapHost = function (node) {
return node && (node.host || unwrapHost(node.parentNode));
};
var correctTargets = function (parent, targets) {
return targets
.map(function (target) {
if (parent.contains(target)) {
return target;
}
var correctedTarget = unwrapHost(target);
if (correctedTarget && parent.contains(correctedTarget)) {
return correctedTarget;
}
console.error('aria-hidden', target, 'in not contained inside', parent, '. Doing nothing');
return null;
})
.filter(function (x) { return Boolean(x); });
};
/**
* Marks everything except given node(or nodes) as aria-hidden
* @param {Element | Element[]} originalTarget - elements to keep on the page
* @param [parentNode] - top element, defaults to document.body
* @param {String} [markerName] - a special attribute to mark every node
* @param {String} [controlAttribute] - html Attribute to control
* @return {Undo} undo command
*/
var applyAttributeToOthers = function (originalTarget, parentNode, markerName, controlAttribute) {
var targets = correctTargets(parentNode, Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
if (!markerMap[markerName]) {
markerMap[markerName] = new WeakMap();
}
var markerCounter = markerMap[markerName];
var hiddenNodes = [];
var elementsToKeep = new Set();
var elementsToStop = new Set(targets);
var keep = function (el) {
if (!el || elementsToKeep.has(el)) {
return;
}
elementsToKeep.add(el);
keep(el.parentNode);
};
targets.forEach(keep);
var deep = function (parent) {
if (!parent || elementsToStop.has(parent)) {
return;
}
Array.prototype.forEach.call(parent.children, function (node) {
if (elementsToKeep.has(node)) {
deep(node);
}
else {
var attr = node.getAttribute(controlAttribute);
var alreadyHidden = attr !== null && attr !== 'false';
var counterValue = (counterMap.get(node) || 0) + 1;
var markerValue = (markerCounter.get(node) || 0) + 1;
counterMap.set(node, counterValue);
markerCounter.set(node, markerValue);
hiddenNodes.push(node);
if (counterValue === 1 && alreadyHidden) {
uncontrolledNodes.set(node, true);
}
if (markerValue === 1) {
node.setAttribute(markerName, 'true');
}
if (!alreadyHidden) {
node.setAttribute(controlAttribute, 'true');
}
}
});
};
deep(parentNode);
elementsToKeep.clear();
lockCount++;
return function () {
hiddenNodes.forEach(function (node) {
var counterValue = counterMap.get(node) - 1;
var markerValue = markerCounter.get(node) - 1;
counterMap.set(node, counterValue);
markerCounter.set(node, markerValue);
if (!counterValue) {
if (!uncontrolledNodes.has(node)) {
node.removeAttribute(controlAttribute);
}
uncontrolledNodes.delete(node);
}
if (!markerValue) {
node.removeAttribute(markerName);
}
});
lockCount--;
if (!lockCount) {
// clear
counterMap = new WeakMap();
counterMap = new WeakMap();
uncontrolledNodes = new WeakMap();
markerMap = {};
}
};
};
/**
* Marks everything except given node(or nodes) as aria-hidden
* @param {Element | Element[]} originalTarget - elements to keep on the page
* @param [parentNode] - top element, defaults to document.body
* @param {String} [markerName] - a special attribute to mark every node
* @return {Undo} undo command
*/
var hideOthers = function (originalTarget, parentNode, markerName) {
if (markerName === void 0) { markerName = 'data-aria-hidden'; }
var targets = Array.from(Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
var activeParentNode = parentNode || getDefaultParent(originalTarget);
if (!activeParentNode) {
return function () { return null; };
}
// we should not hide ariaLive elements - https://github.com/theKashey/aria-hidden/issues/10
targets.push.apply(targets, Array.from(activeParentNode.querySelectorAll('[aria-live]')));
return applyAttributeToOthers(targets, activeParentNode, markerName, 'aria-hidden');
};
/* -------------------------------------------------------------------------------------------------
* Dialog
* -----------------------------------------------------------------------------------------------*/ const $5d3850c4d0b4e6c7$var$DIALOG_NAME = 'Dialog';
const [$5d3850c4d0b4e6c7$var$createDialogContext, $5d3850c4d0b4e6c7$export$cc702773b8ea3e41] = $c512c27ab02ef895$export$50c7b4e9d9f19c1($5d3850c4d0b4e6c7$var$DIALOG_NAME);
const [$5d3850c4d0b4e6c7$var$DialogProvider, $5d3850c4d0b4e6c7$var$useDialogContext] = $5d3850c4d0b4e6c7$var$createDialogContext($5d3850c4d0b4e6c7$var$DIALOG_NAME);
const $5d3850c4d0b4e6c7$export$3ddf2d174ce01153 = (props)=>{
const { __scopeDialog: __scopeDialog , children: children , open: openProp , defaultOpen: defaultOpen , onOpenChange: onOpenChange , modal: modal = true } = props;
const triggerRef = useRef(null);
const contentRef = useRef(null);
const [open = false, setOpen] = $71cd76cc60e0454e$export$6f32135080cb4c3({
prop: openProp,
defaultProp: defaultOpen,
onChange: onOpenChange
});
return /*#__PURE__*/ createElement($5d3850c4d0b4e6c7$var$DialogProvider, {
scope: __scopeDialog,
triggerRef: triggerRef,
contentRef: contentRef,
contentId: $1746a345f3d73bb7$export$f680877a34711e37(),
titleId: $1746a345f3d73bb7$export$f680877a34711e37(),
descriptionId: $1746a345f3d73bb7$export$f680877a34711e37(),
open: open,
onOpenChange: setOpen,
onOpenToggle: useCallback(()=>setOpen((prevOpen)=>!prevOpen
)
, [
setOpen
]),
modal: modal
}, children);
};
/* -------------------------------------------------------------------------------------------------
* DialogPortal
* -----------------------------------------------------------------------------------------------*/ const $5d3850c4d0b4e6c7$var$PORTAL_NAME = 'DialogPortal';
const [$5d3850c4d0b4e6c7$var$PortalProvider, $5d3850c4d0b4e6c7$var$usePortalContext] = $5d3850c4d0b4e6c7$var$createDialogContext($5d3850c4d0b4e6c7$var$PORTAL_NAME, {
forceMount: undefined
});
/* -------------------------------------------------------------------------------------------------
* DialogOverlay
* -----------------------------------------------------------------------------------------------*/ const $5d3850c4d0b4e6c7$var$OVERLAY_NAME = 'DialogOverlay';
const $5d3850c4d0b4e6c7$export$bd1d06c79be19e17 = /*#__PURE__*/ forwardRef((props, forwardedRef)=>{
const portalContext = $5d3850c4d0b4e6c7$var$usePortalContext($5d3850c4d0b4e6c7$var$OVERLAY_NAME, props.__scopeDialog);
const { forceMount: forceMount = portalContext.forceMount , ...overlayProps } = props;
const context = $5d3850c4d0b4e6c7$var$useDialogContext($5d3850c4d0b4e6c7$var$OVERLAY_NAME, props.__scopeDialog);
return context.modal ? /*#__PURE__*/ createElement($921a889cee6df7e8$export$99c2b779aa4e8b8b, {
present: forceMount || context.open
}, /*#__PURE__*/ createElement($5d3850c4d0b4e6c7$var$DialogOverlayImpl, _extends({}, overlayProps, {
ref: forwardedRef
}))) : null;
});
const $5d3850c4d0b4e6c7$var$DialogOverlayImpl = /*#__PURE__*/ forwardRef((props, forwardedRef)=>{
const { __scopeDialog: __scopeDialog , ...overlayProps } = props;
const context = $5d3850c4d0b4e6c7$var$useDialogContext($5d3850c4d0b4e6c7$var$OVERLAY_NAME, __scopeDialog);
return(/*#__PURE__*/ // Make sure `Content` is scrollable even when it doesn't live inside `RemoveScroll`
// ie. when `Overlay` and `Content` are siblings
createElement($67UHm$RemoveScroll, {
as: $5e63c961fc1ce211$export$8c6ed5c666ac1360,
allowPinchZoom: true,
shards: [
context.contentRef
]
}, /*#__PURE__*/ createElement($8927f6f2acc4f386$export$250ffa63cdc0d034.div, _extends({
"data-state": $5d3850c4d0b4e6c7$var$getState(context.open)
}, overlayProps, {
ref: forwardedRef // We re-enable pointer-events prevented by `Dialog.Content` to allow scrolling the overlay.
,
style: {
pointerEvents: 'auto',
...overlayProps.style
}
}))));
});
/* -------------------------------------------------------------------------------------------------
* DialogContent
* -----------------------------------------------------------------------------------------------*/ const $5d3850c4d0b4e6c7$var$CONTENT_NAME = 'DialogContent';
const $5d3850c4d0b4e6c7$export$b6d9565de1e068cf = /*#__PURE__*/ forwardRef((props, forwardedRef)=>{
const portalContext = $5d3850c4d0b4e6c7$var$usePortalContext($5d3850c4d0b4e6c7$var$CONTENT_NAME, props.__scopeDialog);
const { forceMount: forceMount = portalContext.forceMount , ...contentProps } = props;
const context = $5d3850c4d0b4e6c7$var$useDialogContext($5d3850c4d0b4e6c7$var$CONTENT_NAME, props.__scopeDialog);
return /*#__PURE__*/ createElement($921a889cee6df7e8$export$99c2b779aa4e8b8b, {
present: forceMount || context.open
}, context.modal ? /*#__PURE__*/ createElement($5d3850c4d0b4e6c7$var$DialogContentModal, _extends({}, contentProps, {
ref: forwardedRef
})) : /*#__PURE__*/ createElement($5d3850c4d0b4e6c7$var$DialogContentNonModal, _extends({}, contentProps, {
ref: forwardedRef
})));
});
/* -----------------------------------------------------------------------------------------------*/ const $5d3850c4d0b4e6c7$var$DialogContentModal = /*#__PURE__*/ forwardRef((props, forwardedRef)=>{
const context = $5d3850c4d0b4e6c7$var$useDialogContext($5d3850c4d0b4e6c7$var$CONTENT_NAME, props.__scopeDialog);
const contentRef = useRef(null);
const composedRefs = $6ed0406888f73fc4$export$c7b2cbe3552a0d05(forwardedRef, context.contentRef, contentRef); // aria-hide everything except the content (better supported equivalent to setting aria-modal)
useEffect(()=>{
const content = contentRef.current;
if (content) return hideOthers(content);
}, []);
return /*#__PURE__*/ createElement($5d3850c4d0b4e6c7$var$DialogContentImpl, _extends({}, props, {
ref: composedRefs // we make sure focus isn't trapped once `DialogContent` has been closed
,
trapFocus: context.open,
disableOutsidePointerEvents: true,
onCloseAutoFocus: $e42e1063c40fb3ef$export$b9ecd428b558ff10(props.onCloseAutoFocus, (event)=>{
var _context$triggerRef$c;
event.preventDefault();
(_context$triggerRef$c = context.triggerRef.current) === null || _context$triggerRef$c === void 0 || _context$triggerRef$c.focus();
}),
onPointerDownOutside: $e42e1063c40fb3ef$export$b9ecd428b558ff10(props.onPointerDownOutside, (event)=>{
const originalEvent = event.detail.originalEvent;
const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;
const isRightClick = originalEvent.button === 2 || ctrlLeftClick; // If the event is a right-click, we shouldn't close because
// it is effectively as if we right-clicked the `Overlay`.
if (isRightClick) event.preventDefault();
}) // When focus is trapped, a `focusout` event may still happen.
,
onFocusOutside: $e42e1063c40fb3ef$export$b9ecd428b558ff10(props.onFocusOutside, (event)=>event.preventDefault()
)
}));
});
/* -----------------------------------------------------------------------------------------------*/ const $5d3850c4d0b4e6c7$var$DialogContentNonModal = /*#__PURE__*/ forwardRef((props, forwardedRef)=>{
const context = $5d3850c4d0b4e6c7$var$useDialogContext($5d3850c4d0b4e6c7$var$CONTENT_NAME, props.__scopeDialog);
const hasInteractedOutsideRef = useRef(false);
const hasPointerDownOutsideRef = useRef(false);
return /*#__PURE__*/ createElement($5d3850c4d0b4e6c7$var$DialogContentImpl, _extends({}, props, {
ref: forwardedRef,
trapFocus: false,
disableOutsidePointerEvents: false,
onCloseAutoFocus: (event)=>{
var _props$onCloseAutoFoc;
(_props$onCloseAutoFoc = props.onCloseAutoFocus) === null || _props$onCloseAutoFoc === void 0 || _props$onCloseAutoFoc.call(props, event);
if (!event.defaultPrevented) {
var _context$triggerRef$c2;
if (!hasInteractedOutsideRef.current) (_context$triggerRef$c2 = context.triggerRef.current) === null || _context$triggerRef$c2 === void 0 || _context$triggerRef$c2.focus(); // Always prevent auto focus because we either focus manually or want user agent focus
event.preventDefault();
}
hasInteractedOutsideRef.current = false;
hasPointerDownOutsideRef.current = false;
},
onInteractOutside: (event)=>{
var _props$onInteractOuts, _context$triggerRef$c3;
(_props$onInteractOuts = props.onInteractOutside) === null || _props$onInteractOuts === void 0 || _props$onInteractOuts.call(props, event);
if (!event.defaultPrevented) {
hasInteractedOutsideRef.current = true;
if (event.detail.originalEvent.type === 'pointerdown') hasPointerDownOutsideRef.current = true;
} // Prevent dismissing when clicking the trigger.
// As the trigger is already setup to close, without doing so would
// cause it to close and immediately open.
const target = event.target;
const targetIsTrigger = (_context$triggerRef$c3 = context.triggerRef.current) === null || _context$triggerRef$c3 === void 0 ? void 0 : _context$triggerRef$c3.contains(target);
if (targetIsTrigger) event.preventDefault(); // On Safari if the trigger is inside a container with tabIndex={0}, when clicked
// we will get the pointer down outside event on the trigger, but then a subsequent
// focus outside event on the container, we ignore any focus outside event when we've
// already had a pointer down outside event.
if (event.detail.originalEvent.type === 'focusin' && hasPointerDownOutsideRef.current) event.preventDefault();
}
}));
});
/* -----------------------------------------------------------------------------------------------*/ const $5d3850c4d0b4e6c7$var$DialogContentImpl = /*#__PURE__*/ forwardRef((props, forwardedRef)=>{
const { __scopeDialog: __scopeDialog , trapFocus: trapFocus , onOpenAutoFocus: onOpenAutoFocus , onCloseAutoFocus: onCloseAutoFocus , ...contentProps } = props;
const context = $5d3850c4d0b4e6c7$var$useDialogContext($5d3850c4d0b4e6c7$var$CONTENT_NAME, __scopeDialog);
const contentRef = useRef(null);
const composedRefs = $6ed0406888f73fc4$export$c7b2cbe3552a0d05(forwardedRef, contentRef); // Make sure the whole tree has focus guards as our `Dialog` will be
// the last element in the DOM (beacuse of the `Portal`)
$3db38b7d1fb3fe6a$export$b7ece24a22aeda8c();
return /*#__PURE__*/ createElement(Fragment, null, /*#__PURE__*/ createElement($d3863c46a17e8a28$export$20e40289641fbbb6, {
asChild: true,
loop: true,
trapped: trapFocus,
onMountAutoFocus: onOpenAutoFocus,
onUnmountAutoFocus: onCloseAutoFocus
}, /*#__PURE__*/ createElement($5cb92bef7577960e$export$177fb62ff3ec1f22, _extends({
role: "dialog",
id: context.contentId,
"aria-describedby": context.descriptionId,
"aria-labelledby": context.titleId,
"data-state": $5d3850c4d0b4e6c7$var$getState(context.open)
}, contentProps, {
ref: composedRefs,
onDismiss: ()=>context.onOpenChange(false)
}))), false);
});
/* -----------------------------------------------------------------------------------------------*/ function $5d3850c4d0b4e6c7$var$getState(open) {
return open ? 'open' : 'closed';
}
const $5d3850c4d0b4e6c7$export$be92b6f5f03c0fe9 = $5d3850c4d0b4e6c7$export$3ddf2d174ce01153;
const $5d3850c4d0b4e6c7$export$c6fdb837b070b4ff = $5d3850c4d0b4e6c7$export$bd1d06c79be19e17;
const $5d3850c4d0b4e6c7$export$7c6e2c02157bb7d2 = $5d3850c4d0b4e6c7$export$b6d9565de1e068cf;
function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);else for(t in e)e[t]&&(n&&(n+=" "),n+=t);return n}function clsx(){for(var e,t,f=0,n="";f<arguments.length;)(e=arguments[f++])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
const ModalContext = React__default.createContext({
portalRef: void 0,
isLargeModal: true
});
const Overlay = ({ children }) => {
return /* @__PURE__ */ jsx($5d3850c4d0b4e6c7$export$c6fdb837b070b4ff, { className: "bg-grey-90/40 fixed top-0 bottom-0 left-0 right-0 z-50 grid place-items-center overflow-y-auto", children });
};
const Content = ({ children }) => {
const height = window.innerHeight;
const style = {
maxHeight: height - 64
};
return /* @__PURE__ */ jsx(
$5d3850c4d0b4e6c7$export$7c6e2c02157bb7d2,
{
style,
className: "min-w-modal rounded-rounded bg-grey-0 overflow-x-hidden",
children
}
);
};
const Modal = ({
open = true,
handleClose,
isLargeModal = true,
children
}) => {
const portalRef = React__default.useRef(null);
return /* @__PURE__ */ jsx($5d3850c4d0b4e6c7$export$be92b6f5f03c0fe9, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsx($f1701beae083dbae$export$602eac185826482c, { ref: portalRef, children: /* @__PURE__ */ jsx(ModalContext.Provider, { value: { portalRef, isLargeModal }, children: /* @__PURE__ */ jsx(Overlay, { children: /* @__PURE__ */ jsx(Content, { children }) }) }) }) });
};
Modal.Body = ({ children, className, style }) => {
React__default.useContext(ModalContext);
return /* @__PURE__ */ jsx(
"div",
{
style,
className: clsx("inter-base-regular h-full", className),
onClick: (e) => e.stopPropagation(),
children
}
);
};
Modal.Content = ({ children, className }) => {
const { isLargeModal } = React__default.useContext(ModalContext);
const height = window.innerHeight;
const style = {
maxHeight: height - 90 - 141
};
return /* @__PURE__ */ jsx(
"div",
{
style,
className: clsx(
"overflow-y-auto px-8 pt-6",
{
["w-largeModal pb-7"]: isLargeModal,
["pb-5"]: !isLargeModal
},
className
),
children
}
);
};
Modal.Header = ({ handleClose = void 0, children }) => {
return /* @__PURE__ */ jsxs(
"div",
{
className: "flex w-full items-center border-b px-8 py-6",
onClick: (e) => e.stopPropagation(),
children: [
/* @__PURE__ */ jsx("div", { className: "flex flex-grow", children }),
/* @__PURE__ */ jsx("div", { className: "self-end", children: handleClose && /* @__PURE__ */ jsx(
IconButton,
{
variant: "primary",
size: "base",
onClick: handleClose,
className: "text-grey-50 cursor-pointer border p-1.5",
children: /* @__PURE__ */ jsx("div", { className: "flex", children: /* @__PURE__ */ jsx(XMark, {}) })
}
) })
]
}
);
};
Modal.Footer = ({ children, className }) => {
const { isLargeModal } = React__default.useContext(ModalContext);
return /* @__PURE__ */ jsx(
"div",
{
onClick: (e) => e.stopPropagation(),
className: clsx(
"bottom-0 flex w-full px-7 pb-5",
{
"border-grey-20 border-t pt-4": isLargeModal
},
className
),
children
}
);
};
const ReviewDetailsModal = ({
open,
close,
images
}) => {
return /* @__PURE__ */ jsx(Modal, { open, handleClose: close, isLargeModal: true, children: /* @__PURE__ */ jsxs(Modal.Body, { children: [
/* @__PURE__ */ jsx(Modal.Header, { handleClose: close, children: /* @__PURE__ */ jsx("h1", { className: "inter-xlarge-semibold m-0", children: "Review Images" }) }),
/* @__PURE__ */ jsx(Modal.Content, { children: /* @__PURE__ */ jsx("div", { className: "w-full h-[calc(100vh-283px)]", children: /* @__PURE__ */ jsx(
Carousel,
{
hasMediaButton: false,
hasSizeButton: false,
hasIndexBoard: false,
thumbnails: images.map((image, index) => /* @__PURE__ */ jsx(
"img",
{
src: image.url,
alt: image.id,
className: "w-full h-full object-cover !rounded-[3rem]"
},
index
)),
thumbnailWidth: "80px",
thumbnailHeight: "80px",
leftIcon: /* @__PURE__ */ jsx(
IconButton,
{
size: "base",
className: "text-grey-50 cursor-pointer border p-1.5 ml-1.5",
children: /* @__PURE__ */ jsx("div", { className: "flex", children: /* @__PURE__ */ jsx(ChevronLeft, {}) })
}
),
rightIcon: /* @__PURE__ */ jsx(
IconButton,
{
size: "base",
className: "text-grey-50 cursor-pointer border p-1.5 mr-1.5",
children: /* @__PURE__ */ jsx("div", { className: "flex", children: /* @__PURE__ */ jsx(ChevronRight, {}) })
}
),
children: images.map((image, index) => /* @__PURE__ */ jsx("div", { className: "h-full w-full flex items-center bg-black rounded-lg", children: /* @__PURE__ */ jsx(
"img",
{
src: image.url,
alt: image.id,
className: "w-full h-full object-contain"
},
index
) }))
}
) }) })
] }) });
};
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
const calculateSentiment = (rating) => {
if (rating === 3) {
return "Neutral";
}
return rating > 3 ? "Positive" : "Negative";
};
function ReviewDetails({
setPagingState,
pagingState,
pageLimit,
reviewDetails
}) {
var _a;
const [state, open, close] = useToggleState();
const [images, setImages] = useState([]);
const prevPage = () => {
if (pagingState.currentPage !== 1) {
setPagingState(__spreadProps(__spreadValues({}, pagingState), {
currentPage: pagingState.currentPage - 1
}));
}
};
const nextPage = () => {
if (pagingState.currentPage < (reviewDetails == null ? void 0 : reviewDetails.total_pages)) {
setPagingState(__spreadProps(__spreadValues({}, pagingState), {
currentPage: pagingState.currentPage + 1
}));
}
};
const startIndex = (reviewDetails == null ? void 0 : reviewDetails.total_ratings) === 0 ? 0 : (pagingState.currentPage - 1) * pageLimit + 1;
const endIndex = Math.min(
pagingState.currentPage * pageLimit,
(reviewDetails == null ? void 0 : reviewDetails.total_ratings) || 0
);
const previewImages = (i) => {
setImages(reviewDetails.reviews[i].images);
reviewDetails.reviews[i].images.length && open();
};
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
/* @__PURE__ */ jsx(ReviewDetailsModal, { open: state, close, images }),
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
/* @__PURE__ */ jsx("h2", { className: "inter-large-semibold", children: "Reviews details" }),
/* @__PURE__ */ jsxs(Table, { children: [
/* @__PURE__ */ jsx(Table.Header, { className: "text-grey-50", children: /* @__PURE__ */ jsxs(Table.Row, { children: [
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Reviewer Name" }),
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Review" }),
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Rating" }),
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Sentiment" }),
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Images" })
] }) }),
/* @__PURE__ */ jsx(Table.Body, { children: (reviewDetails == null ? void 0 : reviewDetails.reviews) && ((_a = reviewDetails == null ? void 0 : reviewDetails.reviews) == null ? void 0 : _a.length) > 0 && reviewDetails.reviews.map((item, index) => {
var _a2, _b;
let name = ((_a2 = item == null ? void 0 : item.customer) == null ? void 0 : _a2.first_name) + " " + item.customer.last_name;
return /* @__PURE__ */ jsxs(
Table.Row,
{
className: "cursor-pointer",
onClick: () => previewImages(index),
children: [
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
/* @__PURE__ */ jsx(Avatar, { fallback: name.charAt(0).toUpperCase() }),
name
] }) }),
/* @__PURE__ */ jsx(Table.Cell, { children: item.title || "-" }),
/* @__PURE__ */ jsx(Table.Cell, { children: item.rating }),
/* @__PURE__ */ jsx(Table.Cell, { children: calculateSentiment(item.rating) }),
/* @__PURE__ */ jsx(Table.Cell, { children: item.images.length === 0 ? "-" : /* @__PURE__ */ jsxs("div", { className: "relative h-16 w-16 border rounded-md overflow-hidden my-1", children: [
/* @__PURE__ */ jsx(
"img",
{
src: (_b = item.images[0]) == null ? void 0 : _b.url,
alt: name,
className: "h-full w-full object-cover",
onClick: () => {
}
}
),
item.images.length > 1 && /* @__PURE__ */ jsx("div", { className: "absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-white h-full w-full bg-black bg-opacity-50 flex justify-center items-center", children: /* @__PURE__ */ jsxs("p", { className: "text-base", children: [
"+",
item.images.length
] }) })
] }) })
]
},
index
);
}) })
] }),
/* @__PURE__ */ jsxs(
"div",
{
className: "inter-small-regular text-grey-50 flex w-full justify-between",
children: [
/* @__PURE__ */ jsxs("div", { children: [
startIndex,
" - ",
endIndex,
" of ",
(reviewDetails == null ? void 0 : reviewDetails.total_ratings) || 0,
" ",
"Review"
] }),
/* @__PURE__ */ jsxs("div", { className: "flex space-x-4", children: [
/* @__PURE__ */ jsxs("div", { children: [
pagingState.currentPage,
" of ",
reviewDetails == null ? void 0 : reviewDetails.total_pages
] }),
/* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-4", children: [
/* @__PURE__ */ jsx(
"button",
{
className: "disabled:text-grey-30 cursor-pointer disabled:cursor-default",
disabled: pagingState.currentPage === 1 || pagingState.isLoading,
onClick: () => prevPage(),
children: /* @__PURE__ */ jsx(ArrowLeftMini, {})
}
),
/* @__PURE__ */ jsx(
"button",
{
className: "disabled:text-grey-30 cursor-pointer disabled:cursor-default",
disabled: pagingState.currentPage < (reviewDetails == null ? void 0 : reviewDetails.total_pages) ? false : true,
onClick: () => nextPage(),
children: /* @__PURE__ */ jsx(ArrowRightMini, {})
}
)
] })
] })
]
}
)
] })
] });
}
const CSS = `._2ILZE {
position: relative;
width: 100%;
height: 100%;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
display: flex;
background-color: #fff;
flex-flow: column;
align-items: stretch;
box-sizing: border-box;
}
._1_Dg2 {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 2000;
width: 100%;
height: 100%;
background-color: #fff;
transform: scale(1);
transform-origin: top center;
display: flex;
flex-flow: column;
align-items: stretch;
}
._2qwzr {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
flex: 0 1 auto;
}
._Pfcmb {
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
justify-content: flex-start;
align-items: flex-start;
touch-action: auto;
flex: 0 1 auto;
}
._3q7r8 {
background-color: #000;
}
[data-is-not-keyboard-user='true'] *:focus {
outline: none;
}
._L8X8r {
height: 100%;
width: 100%;
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: flex-start;
transform: translateZ(0);
transition-duration: 0s;
transition-property: transform;
transition-timing-function: linear;
will-change: transform;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
._L8X8r._or-gG {
flex-direction: row-reverse;
}
._FP5OY {
cursor: -webkit-grab;
cursor: grab;
}
.isGrabbing > ._FP5OY {
cursor: -webkit-grabbing;
cursor: grabbing;
}
._1eGao {
height: 100%;
min-width: 100%;
width: 100%;
max-width: 100%;
}
._3iVQ0 {
position: relative;
height: 100%;
width: 100%;
margin: 0;
border: 0;
border-image-width: 0;
padding: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
overflow: hidden;
}
._t1897 {
position: relative;
height: 100%;
width: 100%;
margin: 0;
border: 0;
border-image-width: 0;
padding: 0;
-o-object-fit: cover;
object-fit: cover;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-user-drag: none;
}
._1BRif {
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
-o-object-fit: cover;
object-fit: cover;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-user-drag: none;
}
._1BRif._3UdL5 {
display: none;
}
._1BRif::before,
._t1897::before {
content: '';
display: block;
position: absolute;
width: 100%;
min-width: 100%;
height: 100%;
min-height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #444;
}
._3lwW_ {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
}
._1zlZS {
opacity: 0.25;
pointer-events: none;
cursor: not-allowed;
}
._1R7KP {
height: 50px;
padding: 0 10px 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
cursor: text;
}
._1OkCh {
width: 100%;
max-width: 100%;
max-height: 100%;
overflow: auto;
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
cursor: text;
}
.__JnHV {
background: #fff;
font-weight: bold;
padding: 5px;
opacity: 0.75;
height: -webkit-min-content;
height: -moz-min-content;
height: min-content;
}
._3lLfB {
filter: drop-shadow(0px 0px 5px #888);
}
._14Fp5 {
height: 100%;
overflow-x: hidden;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
flex-wrap: wrap;
}
._14Fp5._3Rfma {
flex-direction: row-reverse;
}
/*center positions*/
._1cqA3 {
top: 50%;
left: 0;
transform: translateY(-50%);
}
._2GizQ {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
._2zEIf {
top: 50%;
right: 0;
transform: translateY(-50%);
}
/*top positions*/
._lhmht {
top: 0;
left: 0;
}
._29p_Y {
top: 0;
left: 0;
right: 0;
margin: 0 auto;
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
._3r4Pe {
top: 0;
left: 0;
right: 0;
margin: 0 auto;
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
._1oKnM {
top: 0;
right: 0;
}
/*bottom positions*/
._2A4to {
bottom: 0;
left: 0;
}
._3apmu {
bottom: 0;
left: 0;
right: 0;
margin: 0 auto;
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
._2ljUm {
bottom: 0;
left: 0;
right: 0;
margin: 0 auto;
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
._3XvNX {
bottom: 0;
right: 0;
}
._ZTBlf {
position: relative;
margin: 0;
border: none;
padding: 0;
display: inline-block;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
opacity: 0.75;
background-color: transparent;
background-position: center;
background-repeat: no-repeat;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
touch-action: manipulation;
}
._3LX_O {
filter: drop-shadow(0px 0px 3px #888);
}
._ZTBlf:hover {
opacity: 1;
}
@media (hover: none) {
._ZTBlf:hover {
opacity: 0.75;
}
}
._lfOsC {
display: flex;
justify-content: center;
align-items: center;
}
._1Pekn {
width: 50px;
height: 60px;
}
._dZ8C- {
width: 50px;
height: 50px;
}
._20GWq {
width: 20px;
height: 20px;
border-radius: 50%;
}
._3WRGR {
stroke: #bbb;
stroke-opacity: 1;
stroke-width: 1px;
fill: #fff;
}
._1JHpX {
height: 100%;
width: 100%;
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
overflow-wrap: break-word;
word-break: normal;
white-space: normal;
-webkit-user-select: auto;
-moz-user-select: auto;
-ms-user-select: auto;
user-select: auto; }
._XQjA1 {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-ms-zoom: 10%;
zoom: 10%;
font-size: 10%;
-webkit-text-size-adjust: none;
-moz-text-size-adjust: none;
text-size-adjust: none;
pointer-events: none; }
._XQjA1 * {
-webkit-text-size-adjust: none;
-moz-text-size-adjust: none;
text-size-adjust: none; }
._XQjA1 > * {
pointer-events: none; }
/*Only for Chrome, Opera and Edge*/
@media screen and (-webkit-min-device-pixel-ratio: 0) and (min-resolution: 0.001dpcm) {
._XQjA1 {
font-size: 100%; } }
/*Only for FireFox*/
@-moz-document url-prefix() {
._XQjA1 {
font-size: 10%; } }
._2c50p {
flex: 0 0 10%;
margin: 3px 0 0;
padding: 0;
overflow-y: hidden;
overflow-x: scroll;
cursor: -webkit-grab;
cursor: grab;
scrollbar-width: none;
/* Prevent the default behaviour of "scroll chaining" where parent element
gets scrolled when the child element is over scrolled,
in order to prevent going to the previous or the next page. */
overflow-scrolling: auto;
-webkit-overflow-scrolling: touch;
-ms-scroll-chaining: none;
overscroll-behavior-x: contain;
-ms-overflow-style: none; }
.isGrabbing._2c50p {
cursor: -webkit-grabbing;
cursor: grabbing; }
._2c50p::-webkit-scrollbar {
display: none; }
._-LJ2W {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: flex-start; }
._-LJ2W._3NsOQ {
flex-direction: row-reverse;
/*thumbnails would be frozen (can not be scrolled) with justify-content: flex-start;*/
justify-content: flex-end; }
._-cAh3 {
display: block;
height: 100%;
min-width: 10%;
width: 10%;
max-width: 10%;
overflow: hidden;
margin-right: 3px;
padding: 0;
opacity: 0.5;
list-style: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-user-drag: none; }
._19gvi {
opacity: 1; }
._-cAh3:not(._19gvi):hover {
opacity: 1; }
/* prevent thumbnail to stay in the hover state on touch devices,
since there is no such thing as "hover" on touch devices */
@media (hover: none) {
._-cAh3:not(._19gvi):hover {
opacity: 0.5; } }
`;
const pageLimit = 5;
const ProductWidget = (props) => {
var _a;
const { product } = props;
const [pagingState, setPagingState] = useState({
isLoading: false,
currentPage: 1,
totalPage: 1
});
const { data } = useAdminCustomQuery(
`/reviews/${product.id}`,
["review", product.id],
{
limit: pageLimit,
page: pagingState.currentPage
}
);
const reviewDetails = {
total_pages: data == null ? void 0 : data.total_pages,
total_ratings: data == null ? void 0 : data.total_ratings,
reviews: (_a = data == null ? void 0 : data.reviews) == null ? void 0 : _a.map(
({ id, description, images, rating, title, customer }) => ({
id,
description,
images,
rating,
title,
customer: {
email: customer == null ? void 0 : customer.email,
first_name: customer == null ? void 0 : customer.first_name,
last_name: customer == null ? void 0 : customer.last_name,
id: customer == null ? void 0 : customer.id
}
})
)
};
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
/* @__PURE__ */ jsx("style", { children: CSS }),
/* @__PURE__ */ jsxs("div", { className: "px-xlarge pt-large pb-xlarge rounded-rounded bg-grey-0 border-grey-20 border", children: [
/* @__PURE__ */ jsx("h1", { className: "text-grey-90 inter-xlarge-semibold", children: "Reviews and Ratings" }),
/* @__PURE__ */ jsx("div", { className: "mt-large mb-xlarge", children: /* @__PURE__ */ jsx(
RatingOverview,
{
starWiseData: data == null ? void 0 : data.star_wise_data,
averageRatings: data == null ? void 0 : data.average_rating,
totalRatings: data == null ? void 0 : data.total_ratings
}
) }),
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
ReviewDetails,
{
reviewDetails,
pageLimit,
pagingState,
setPagingState
}
) })
] })
] });
};
const config = {
zone: "product.details.after"
};
const entry = {
identifier: "medusa-plugin-reviews-and-ratings",
extensions: [
{ Component: ProductWidget, config: { ...config, type: "widget" } }
],
};
export { entry as default };