@expofp/ui 0.0.0-experimental.cf063fc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/dist/components/Alert/Alert.d.ts +20 -0
- package/dist/components/Alert/Alert.js +23 -0
- package/dist/components/Alert/index.d.ts +3 -0
- package/dist/components/Alert/index.js +1 -0
- package/dist/components/Autocomplete/Autocomplete.d.ts +28 -0
- package/dist/components/Autocomplete/Autocomplete.js +292 -0
- package/dist/components/Autocomplete/index.d.ts +3 -0
- package/dist/components/Autocomplete/index.js +1 -0
- package/dist/components/Badge/Badge.d.ts +14 -0
- package/dist/components/Badge/Badge.js +15 -0
- package/dist/components/Badge/index.d.ts +3 -0
- package/dist/components/Badge/index.js +1 -0
- package/dist/components/Button/Button.d.ts +30 -0
- package/dist/components/Button/Button.js +41 -0
- package/dist/components/Button/index.d.ts +3 -0
- package/dist/components/Button/index.js +1 -0
- package/dist/components/Checkbox/Checkbox.d.ts +19 -0
- package/dist/components/Checkbox/Checkbox.js +19 -0
- package/dist/components/Checkbox/index.d.ts +3 -0
- package/dist/components/Checkbox/index.js +1 -0
- package/dist/components/CheckboxButton/CheckboxButton.d.ts +12 -0
- package/dist/components/CheckboxButton/CheckboxButton.js +19 -0
- package/dist/components/CheckboxButton/index.d.ts +3 -0
- package/dist/components/CheckboxButton/index.js +1 -0
- package/dist/components/DownloadList/DownloadList.d.ts +15 -0
- package/dist/components/DownloadList/DownloadList.js +9 -0
- package/dist/components/DownloadList/index.d.ts +3 -0
- package/dist/components/DownloadList/index.js +2 -0
- package/dist/components/Draggable/Draggable.d.ts +9 -0
- package/dist/components/Draggable/Draggable.js +92 -0
- package/dist/components/Draggable/index.d.ts +3 -0
- package/dist/components/Draggable/index.js +2 -0
- package/dist/components/EntityItem/EntityItem.d.ts +46 -0
- package/dist/components/EntityItem/EntityItem.js +29 -0
- package/dist/components/EntityItem/index.d.ts +3 -0
- package/dist/components/EntityItem/index.js +1 -0
- package/dist/components/EventBadge/EventBadge.d.ts +13 -0
- package/dist/components/EventBadge/EventBadge.js +10 -0
- package/dist/components/EventBadge/index.d.ts +3 -0
- package/dist/components/EventBadge/index.js +1 -0
- package/dist/components/Gallery/Gallery.d.ts +24 -0
- package/dist/components/Gallery/Gallery.js +28 -0
- package/dist/components/Gallery/GalleryBadges/GalleryBadges.d.ts +8 -0
- package/dist/components/Gallery/GalleryBadges/GalleryBadges.js +5 -0
- package/dist/components/Gallery/GalleryControls/GalleryControls.d.ts +11 -0
- package/dist/components/Gallery/GalleryControls/GalleryControls.js +5 -0
- package/dist/components/Gallery/GalleryImg/GalleryImg.d.ts +13 -0
- package/dist/components/Gallery/GalleryImg/GalleryImg.js +37 -0
- package/dist/components/Gallery/GalleryItem/GalleryItem.d.ts +14 -0
- package/dist/components/Gallery/GalleryItem/GalleryItem.js +6 -0
- package/dist/components/Gallery/GalleryModal/GalleryModal.d.ts +20 -0
- package/dist/components/Gallery/GalleryModal/GalleryModal.js +90 -0
- package/dist/components/Gallery/GalleryPreLoader.d.ts +7 -0
- package/dist/components/Gallery/GalleryPreLoader.js +29 -0
- package/dist/components/Gallery/TransformImg/TransformImg.d.ts +10 -0
- package/dist/components/Gallery/TransformImg/TransformImg.js +15 -0
- package/dist/components/Gallery/index.d.ts +4 -0
- package/dist/components/Gallery/index.js +1 -0
- package/dist/components/Gallery/types.d.ts +6 -0
- package/dist/components/Gallery/types.js +1 -0
- package/dist/components/HeatmapLegend/HeatmapLegend.d.ts +15 -0
- package/dist/components/HeatmapLegend/HeatmapLegend.js +11 -0
- package/dist/components/HeatmapLegend/index.d.ts +3 -0
- package/dist/components/HeatmapLegend/index.js +2 -0
- package/dist/components/HighlightText/HighlightText.d.ts +7 -0
- package/dist/components/HighlightText/HighlightText.js +14 -0
- package/dist/components/HighlightText/index.d.ts +2 -0
- package/dist/components/HighlightText/index.js +1 -0
- package/dist/components/LevelBadge/LevelBadge.d.ts +9 -0
- package/dist/components/LevelBadge/LevelBadge.js +10 -0
- package/dist/components/LevelBadge/index.d.ts +3 -0
- package/dist/components/LevelBadge/index.js +2 -0
- package/dist/components/LevelSelector/LevelSelector.d.ts +18 -0
- package/dist/components/LevelSelector/LevelSelector.js +91 -0
- package/dist/components/LevelSelector/index.d.ts +3 -0
- package/dist/components/LevelSelector/index.js +2 -0
- package/dist/components/MapControls/MapControls.d.ts +33 -0
- package/dist/components/MapControls/MapControls.js +38 -0
- package/dist/components/MapControls/index.d.ts +3 -0
- package/dist/components/MapControls/index.js +2 -0
- package/dist/components/MobileToggleButton/MobileToggleButton.d.ts +11 -0
- package/dist/components/MobileToggleButton/MobileToggleButton.js +8 -0
- package/dist/components/MobileToggleButton/index.d.ts +3 -0
- package/dist/components/MobileToggleButton/index.js +1 -0
- package/dist/components/Modal/Modal.d.ts +34 -0
- package/dist/components/Modal/Modal.js +103 -0
- package/dist/components/Modal/index.d.ts +3 -0
- package/dist/components/Modal/index.js +1 -0
- package/dist/components/MultiSelectGroups/MultiSelectGroups.d.ts +37 -0
- package/dist/components/MultiSelectGroups/MultiSelectGroups.js +80 -0
- package/dist/components/MultiSelectGroups/index.d.ts +3 -0
- package/dist/components/MultiSelectGroups/index.js +1 -0
- package/dist/components/Overlay/Overlay.d.ts +30 -0
- package/dist/components/Overlay/Overlay.js +250 -0
- package/dist/components/Overlay/OverlayHeaderContext.d.ts +7 -0
- package/dist/components/Overlay/OverlayHeaderContext.js +7 -0
- package/dist/components/Overlay/OverlayKeyboardInsetContext.d.ts +7 -0
- package/dist/components/Overlay/OverlayKeyboardInsetContext.js +7 -0
- package/dist/components/Overlay/OverlayScrollContext.d.ts +7 -0
- package/dist/components/Overlay/OverlayScrollContext.js +7 -0
- package/dist/components/Overlay/index.d.ts +5 -0
- package/dist/components/Overlay/index.js +3 -0
- package/dist/components/OverlayGrip/OverlayGrip.d.ts +11 -0
- package/dist/components/OverlayGrip/OverlayGrip.js +8 -0
- package/dist/components/OverlayGrip/index.d.ts +3 -0
- package/dist/components/OverlayGrip/index.js +2 -0
- package/dist/components/PermissionNotice/PermissionNotice.d.ts +16 -0
- package/dist/components/PermissionNotice/PermissionNotice.js +11 -0
- package/dist/components/PermissionNotice/index.d.ts +3 -0
- package/dist/components/PermissionNotice/index.js +2 -0
- package/dist/components/PlanSelector/PlanSelector.d.ts +13 -0
- package/dist/components/PlanSelector/PlanSelector.js +10 -0
- package/dist/components/PlanSelector/index.d.ts +3 -0
- package/dist/components/PlanSelector/index.js +2 -0
- package/dist/components/Radio/Radio.d.ts +15 -0
- package/dist/components/Radio/Radio.js +13 -0
- package/dist/components/Radio/index.d.ts +3 -0
- package/dist/components/Radio/index.js +1 -0
- package/dist/components/RebookingNotes/RebookingNotes.d.ts +11 -0
- package/dist/components/RebookingNotes/RebookingNotes.js +18 -0
- package/dist/components/RebookingNotes/index.d.ts +3 -0
- package/dist/components/RebookingNotes/index.js +1 -0
- package/dist/components/RebookingRadioGroup/RebookingRadioGroup.d.ts +17 -0
- package/dist/components/RebookingRadioGroup/RebookingRadioGroup.js +13 -0
- package/dist/components/RebookingRadioGroup/index.d.ts +3 -0
- package/dist/components/RebookingRadioGroup/index.js +1 -0
- package/dist/components/ScrollableRow/ScrollableRow.d.ts +21 -0
- package/dist/components/ScrollableRow/ScrollableRow.js +155 -0
- package/dist/components/ScrollableRow/index.d.ts +3 -0
- package/dist/components/ScrollableRow/index.js +2 -0
- package/dist/components/Share/Share.d.ts +22 -0
- package/dist/components/Share/Share.js +24 -0
- package/dist/components/Share/index.d.ts +3 -0
- package/dist/components/Share/index.js +1 -0
- package/dist/components/ShowMoreButton/ShowMoreButton.d.ts +11 -0
- package/dist/components/ShowMoreButton/ShowMoreButton.js +7 -0
- package/dist/components/ShowMoreButton/index.d.ts +3 -0
- package/dist/components/ShowMoreButton/index.js +1 -0
- package/dist/components/SidebarActions/SidebarActions.d.ts +26 -0
- package/dist/components/SidebarActions/SidebarActions.js +32 -0
- package/dist/components/SidebarActions/index.d.ts +3 -0
- package/dist/components/SidebarActions/index.js +2 -0
- package/dist/components/SimpleRow/SimpleRow.d.ts +15 -0
- package/dist/components/SimpleRow/SimpleRow.js +11 -0
- package/dist/components/SimpleRow/index.d.ts +3 -0
- package/dist/components/SimpleRow/index.js +2 -0
- package/dist/components/Spinner/Spinner.d.ts +9 -0
- package/dist/components/Spinner/Spinner.js +8 -0
- package/dist/components/Spinner/index.d.ts +3 -0
- package/dist/components/Spinner/index.js +1 -0
- package/dist/components/ToggleButton/ToggleButton.d.ts +17 -0
- package/dist/components/ToggleButton/ToggleButton.js +8 -0
- package/dist/components/ToggleButton/index.d.ts +3 -0
- package/dist/components/ToggleButton/index.js +1 -0
- package/dist/components/ToggleSwitch/ToggleSwitch.d.ts +12 -0
- package/dist/components/ToggleSwitch/ToggleSwitch.js +10 -0
- package/dist/components/ToggleSwitch/index.d.ts +3 -0
- package/dist/components/ToggleSwitch/index.js +1 -0
- package/dist/components/TouchHand/TouchHand.d.ts +5 -0
- package/dist/components/TouchHand/TouchHand.js +7 -0
- package/dist/components/TouchHand/index.d.ts +2 -0
- package/dist/components/TouchHand/index.js +1 -0
- package/dist/components/VenuePicker/VenuePicker.d.ts +23 -0
- package/dist/components/VenuePicker/VenuePicker.js +70 -0
- package/dist/components/VenuePicker/index.d.ts +3 -0
- package/dist/components/VenuePicker/index.js +2 -0
- package/dist/components/WayfindingFloorSelector/WayfindingFloorSelector.d.ts +24 -0
- package/dist/components/WayfindingFloorSelector/WayfindingFloorSelector.js +27 -0
- package/dist/components/WayfindingFloorSelector/index.d.ts +3 -0
- package/dist/components/WayfindingFloorSelector/index.js +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.js +77 -0
- package/dist/shared/activeElement.d.ts +7 -0
- package/dist/shared/activeElement.js +14 -0
- package/dist/shared/debounce.d.ts +2 -0
- package/dist/shared/debounce.js +9 -0
- package/dist/shared/hooks/useKeyboardInset.d.ts +9 -0
- package/dist/shared/hooks/useKeyboardInset.js +84 -0
- package/dist/shared/hooks/useOnClickOutside.d.ts +14 -0
- package/dist/shared/hooks/useOnClickOutside.js +43 -0
- package/dist/shared/hooks/useOnEscape.d.ts +14 -0
- package/dist/shared/hooks/useOnEscape.js +31 -0
- package/dist/shared/hooks/useSheetDrag.d.ts +28 -0
- package/dist/shared/hooks/useSheetDrag.js +274 -0
- package/dist/shared/hooks/useWindowSize.d.ts +5 -0
- package/dist/shared/hooks/useWindowSize.js +38 -0
- package/dist/shared/interactive.d.ts +2 -0
- package/dist/shared/interactive.js +4 -0
- package/dist/shared/selector-option.d.ts +7 -0
- package/dist/shared/selector-option.js +1 -0
- package/package.json +73 -0
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @expofp/ui
|
|
2
|
+
|
|
3
|
+
Shared **pure, presentational** React components for the ExpoFP SDK. Bundled with the packages that
|
|
4
|
+
depend on it — no separate install.
|
|
5
|
+
|
|
6
|
+
**Scope rule:** props-in, markup-out components only — no domain logic, no MobX stores, no data
|
|
7
|
+
fetching, no side effects. Nothing here may know about floor plans, booths, exhibitors, or events, or
|
|
8
|
+
import from a domain package. Components receive everything they render via props; stateful wiring
|
|
9
|
+
(Containers) lives in the consuming package. The test: _could it ship in a general-purpose React
|
|
10
|
+
component library unchanged?_ If not, it belongs next to the domain that owns it.
|
|
11
|
+
|
|
12
|
+
## Styling
|
|
13
|
+
|
|
14
|
+
Components import their own `.scss`, which expects the SDK's shared SCSS layer (design tokens,
|
|
15
|
+
mixins, icon glyphs) via the `@styles` alias. The published package ships **JS only** — no compiled
|
|
16
|
+
CSS and no `.scss` sources. It is therefore consumed **from source** by `@expofp/floorplan`'s bundler
|
|
17
|
+
(the `@expofp/source` export condition), which compiles the SCSS into its own output. `@expofp/ui` is
|
|
18
|
+
an internal building block and is not intended to be styled standalone from its published `dist`.
|
|
19
|
+
|
|
20
|
+
`src/styles` (the primitives `_vars`, `_utils`, `main`, `_icons`) and `public/fonts` are the canonical
|
|
21
|
+
home of this layer — `@expofp/floorplan` points its own `@styles` alias here instead of keeping a
|
|
22
|
+
copy. If a third consumer ever needs it, split it into a dedicated `@expofp/styles` package; until
|
|
23
|
+
then, one extra alias hop is simpler than a package with a single dependent.
|
|
24
|
+
|
|
25
|
+
- Build: `nx build ui`
|
|
26
|
+
- Test (unit): `nx test ui`
|
|
27
|
+
- Test (stories, browser): `nx test-storybook ui`
|
|
28
|
+
- Storybook (dev): `nx storybook ui`
|
|
29
|
+
- Storybook (build): `nx build-storybook ui`
|
|
30
|
+
- Lint: `nx lint ui`
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import './Alert.scss';
|
|
2
|
+
import React, { type ReactNode } from 'react';
|
|
3
|
+
export type AlertVariant = 'info' | 'warning' | 'error' | 'success' | 'blank';
|
|
4
|
+
export type AlertSize = 'sm' | 'md';
|
|
5
|
+
export type AlertPosition = 'top-right' | 'bottom-right';
|
|
6
|
+
export interface AlertProps {
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
position?: AlertPosition;
|
|
9
|
+
variant?: AlertVariant;
|
|
10
|
+
size?: AlertSize;
|
|
11
|
+
inline?: boolean;
|
|
12
|
+
showIcon?: boolean;
|
|
13
|
+
closable?: boolean;
|
|
14
|
+
title?: string;
|
|
15
|
+
closeLabel: string;
|
|
16
|
+
onClose?: () => void;
|
|
17
|
+
}
|
|
18
|
+
declare const Alert: ({ children, position, variant, inline, showIcon, size, closable, title, closeLabel, onClose, }: AlertProps) => React.JSX.Element;
|
|
19
|
+
export default Alert;
|
|
20
|
+
//# sourceMappingURL=Alert.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import './Alert.scss';
|
|
4
|
+
import cn from 'classnames';
|
|
5
|
+
const Alert = ({ children, position, variant = 'info', inline = false, showIcon = true, size = 'md', closable = false, title, closeLabel, onClose, }) => {
|
|
6
|
+
const alertIcon = () => {
|
|
7
|
+
switch (variant) {
|
|
8
|
+
case 'error':
|
|
9
|
+
return 'icon-close-solid';
|
|
10
|
+
case 'success':
|
|
11
|
+
return 'icon-checkmark-solid';
|
|
12
|
+
case 'warning':
|
|
13
|
+
return 'icon-warning-solid';
|
|
14
|
+
default:
|
|
15
|
+
return 'icon-info-solid';
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
return (_jsxs("div", { className: cn('efp-alert', `efp-alert--${variant} efp-alert--${size}`, {
|
|
19
|
+
'efp-alert--inline': inline,
|
|
20
|
+
[`efp-alert--${position}`]: position,
|
|
21
|
+
}), role: variant === 'error' || variant === 'warning' ? 'alert' : 'status', "aria-live": variant === 'error' || variant === 'warning' ? 'assertive' : 'polite', children: [showIcon && (_jsx("div", { className: "efp-alert__icon", children: _jsx("i", { className: cn(alertIcon()), "aria-hidden": "true" }) })), _jsxs("div", { className: "efp-alert__content", children: [title && _jsx("div", { className: "efp-alert__title", children: title }), children] }), closable && (_jsx("button", { type: "button", className: "efp-alert__close", onClick: onClose, "aria-label": closeLabel, title: closeLabel }))] }));
|
|
22
|
+
};
|
|
23
|
+
export default Alert;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Alert';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import './Autocomplete.scss';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export interface AutocompleteOptionObject {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
}
|
|
7
|
+
export interface AutocompleteProps<T extends AutocompleteOptionObject = AutocompleteOptionObject> {
|
|
8
|
+
placeholder: string;
|
|
9
|
+
options: T[];
|
|
10
|
+
value?: T;
|
|
11
|
+
showClear?: boolean;
|
|
12
|
+
onChange?: (value: T | undefined) => void;
|
|
13
|
+
renderTarget?: HTMLElement | null;
|
|
14
|
+
/**
|
|
15
|
+
* Anchor the option list to the input with CSS instead of portalling it and
|
|
16
|
+
* measuring where it should go. The bottom sheet wants this: while the
|
|
17
|
+
* on-screen keyboard pans the viewport, measured coordinates are stale by the
|
|
18
|
+
* time they are written (#1567).
|
|
19
|
+
*/
|
|
20
|
+
inline?: boolean;
|
|
21
|
+
noOptionsLabel: string;
|
|
22
|
+
ariaLabel: string;
|
|
23
|
+
clearLabel: string;
|
|
24
|
+
getOptionKey?: (option: T) => string;
|
|
25
|
+
}
|
|
26
|
+
declare const Autocomplete: <T extends AutocompleteOptionObject = AutocompleteOptionObject>({ placeholder, options, value, showClear, onChange, renderTarget, inline, noOptionsLabel, ariaLabel, clearLabel, getOptionKey, }: AutocompleteProps<T>) => React.JSX.Element;
|
|
27
|
+
export default Autocomplete;
|
|
28
|
+
//# sourceMappingURL=Autocomplete.d.ts.map
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import './Autocomplete.scss';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
import { lazy, Suspense, useContext, useEffect, useId, useMemo, useRef, useState, } from 'react';
|
|
5
|
+
import { createPortal } from 'react-dom';
|
|
6
|
+
import { ResizeObserver } from 'resize-observer';
|
|
7
|
+
import useOnClickOutside from '../../shared/hooks/useOnClickOutside';
|
|
8
|
+
import { OverlayKeyboardInsetContext } from '../Overlay/OverlayKeyboardInsetContext';
|
|
9
|
+
import { OverlayScrollContext } from '../Overlay/OverlayScrollContext';
|
|
10
|
+
const DROPDOWN_GAP = 4;
|
|
11
|
+
/** Below this the list is useless, so it is allowed to overflow the visible area. */
|
|
12
|
+
const DROPDOWN_MIN_HEIGHT = 96;
|
|
13
|
+
/** Share of the visible viewport the list may take (the SCSS counterpart of a `vh` cap). */
|
|
14
|
+
const DROPDOWN_HEIGHT_RATIO = 0.45;
|
|
15
|
+
const Autocomplete = ({ placeholder, options, value, showClear = false, onChange, renderTarget = document.body, inline = false, noOptionsLabel, ariaLabel, clearLabel, getOptionKey = (option) => option.value, }) => {
|
|
16
|
+
const container = renderTarget;
|
|
17
|
+
// The scrollable body of the sheet the inline list must stay inside of.
|
|
18
|
+
const scrollContainer = useContext(OverlayScrollContext);
|
|
19
|
+
const keyboardInset = useContext(OverlayKeyboardInsetContext);
|
|
20
|
+
const refAutocomplete = useRef(null);
|
|
21
|
+
const refSearchInput = useRef(null);
|
|
22
|
+
const refOptions = useRef(null);
|
|
23
|
+
const virtuosoRef = useRef(null);
|
|
24
|
+
// State, not a ref: the list can only mount once its scroll parent exists.
|
|
25
|
+
const [scrollElement, setScrollElement] = useState(null);
|
|
26
|
+
const blurTimeoutRef = useRef(null);
|
|
27
|
+
const listboxId = useId();
|
|
28
|
+
const getOptionId = (index) => `${listboxId}-option-${index}`;
|
|
29
|
+
const getOptionLabel = (option) => option.label;
|
|
30
|
+
const isSameOption = (a, b) => getOptionKey(a) === getOptionKey(b);
|
|
31
|
+
const findOptionIndexByValue = (searchValue) => options.findIndex((option) => isSameOption(option, searchValue));
|
|
32
|
+
const findOptionByValue = (searchValue) => options.find((option) => isSameOption(option, searchValue));
|
|
33
|
+
const [searchText, setSearchText] = useState(null);
|
|
34
|
+
const [focusOptionIndex, setFocusOptionIndex] = useState(null);
|
|
35
|
+
const [showOptionsDropdown, setShowOptionsDropdown] = useState(false);
|
|
36
|
+
const [inlineMaxHeight, setInlineMaxHeight] = useState(null);
|
|
37
|
+
const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0, width: 0, maxHeight: 0 });
|
|
38
|
+
const activeOption = value ? findOptionByValue(value) : undefined;
|
|
39
|
+
const activeOptionIndex = activeOption ? findOptionIndexByValue(activeOption) : null;
|
|
40
|
+
const displayValue = searchText ?? (activeOption ? getOptionLabel(activeOption) : '');
|
|
41
|
+
const filteredOptions = useMemo(() => {
|
|
42
|
+
if (!searchText)
|
|
43
|
+
return [];
|
|
44
|
+
const lower = searchText.toLowerCase();
|
|
45
|
+
return options.filter((option) => getOptionLabel(option).toLowerCase().includes(lower));
|
|
46
|
+
}, [searchText, options]);
|
|
47
|
+
const updateDropdownPosition = () => {
|
|
48
|
+
if (inline || !refAutocomplete.current || !showOptionsDropdown)
|
|
49
|
+
return;
|
|
50
|
+
const rect = refAutocomplete.current.getBoundingClientRect();
|
|
51
|
+
// The visible bounds, not the layout ones: the on-screen keyboard shrinks
|
|
52
|
+
// `visualViewport` while `innerHeight` stays put.
|
|
53
|
+
const viewport = typeof window.visualViewport !== 'undefined' ? window.visualViewport : null;
|
|
54
|
+
const visibleTop = viewport ? viewport.offsetTop : 0;
|
|
55
|
+
const visibleBottom = viewport ? viewport.offsetTop + viewport.height : window.innerHeight;
|
|
56
|
+
const spaceBelow = visibleBottom - rect.bottom - DROPDOWN_GAP;
|
|
57
|
+
const spaceAbove = rect.top - visibleTop - DROPDOWN_GAP;
|
|
58
|
+
// Flip up when the list does not fit below and above is roomier (#1567).
|
|
59
|
+
const desiredHeight = (visibleBottom - visibleTop) * DROPDOWN_HEIGHT_RATIO;
|
|
60
|
+
const openUp = spaceBelow < desiredHeight && spaceAbove > spaceBelow;
|
|
61
|
+
const space = Math.max(openUp ? spaceAbove : spaceBelow, DROPDOWN_MIN_HEIGHT);
|
|
62
|
+
const maxHeight = Math.min(desiredHeight, space);
|
|
63
|
+
// The dropdown is absolutely positioned inside the render target, so both
|
|
64
|
+
// edges are measured against it — never against the document.
|
|
65
|
+
const containerRect = container?.getBoundingClientRect();
|
|
66
|
+
const containerTop = containerRect?.top ?? 0;
|
|
67
|
+
setDropdownPosition({
|
|
68
|
+
...(openUp
|
|
69
|
+
? { bottom: (containerRect?.bottom ?? window.innerHeight) - rect.top + DROPDOWN_GAP }
|
|
70
|
+
: { top: rect.bottom - containerTop + DROPDOWN_GAP }),
|
|
71
|
+
left: rect.left - (containerRect?.left ?? 0),
|
|
72
|
+
width: rect.width,
|
|
73
|
+
maxHeight,
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
if (inline || !showOptionsDropdown)
|
|
78
|
+
return;
|
|
79
|
+
updateDropdownPosition();
|
|
80
|
+
window.addEventListener('scroll', updateDropdownPosition, true);
|
|
81
|
+
window.addEventListener('resize', updateDropdownPosition);
|
|
82
|
+
const viewport = typeof window.visualViewport !== 'undefined' ? window.visualViewport : null;
|
|
83
|
+
viewport?.addEventListener('resize', updateDropdownPosition);
|
|
84
|
+
viewport?.addEventListener('scroll', updateDropdownPosition);
|
|
85
|
+
return () => {
|
|
86
|
+
window.removeEventListener('scroll', updateDropdownPosition, true);
|
|
87
|
+
window.removeEventListener('resize', updateDropdownPosition);
|
|
88
|
+
viewport?.removeEventListener('resize', updateDropdownPosition);
|
|
89
|
+
viewport?.removeEventListener('scroll', updateDropdownPosition);
|
|
90
|
+
};
|
|
91
|
+
}, [showOptionsDropdown, inline]);
|
|
92
|
+
// The inline list ends where the sheet's scroll body does, or at the keyboard
|
|
93
|
+
// when that body runs on under one. Left to overflow, it would extend that
|
|
94
|
+
// body and the tail could only be reached by scrolling the sheet, then the
|
|
95
|
+
// list. Both rects come from the same layout, so the keyboard panning the
|
|
96
|
+
// viewport does not skew the difference.
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (!inline || !showOptionsDropdown || !scrollContainer) {
|
|
99
|
+
setInlineMaxHeight(null);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const measure = () => {
|
|
103
|
+
const anchor = refAutocomplete.current;
|
|
104
|
+
if (!anchor)
|
|
105
|
+
return;
|
|
106
|
+
const room = scrollContainer.getBoundingClientRect().bottom -
|
|
107
|
+
keyboardInset -
|
|
108
|
+
anchor.getBoundingClientRect().bottom -
|
|
109
|
+
DROPDOWN_GAP;
|
|
110
|
+
setInlineMaxHeight(Math.max(room, DROPDOWN_MIN_HEIGHT));
|
|
111
|
+
};
|
|
112
|
+
measure();
|
|
113
|
+
// The sheet resizes under the list: snap points, the keyboard, a drag.
|
|
114
|
+
const observer = new ResizeObserver(measure);
|
|
115
|
+
observer.observe(scrollContainer);
|
|
116
|
+
return () => observer.disconnect();
|
|
117
|
+
}, [inline, showOptionsDropdown, scrollContainer, keyboardInset]);
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
if (focusOptionIndex === null)
|
|
120
|
+
return;
|
|
121
|
+
// Through the list, not the DOM: a focused option far down is not rendered until scrolled to.
|
|
122
|
+
virtuosoRef.current?.scrollIntoView({ index: focusOptionIndex });
|
|
123
|
+
}, [focusOptionIndex]);
|
|
124
|
+
useOnClickOutside([refAutocomplete, refOptions], () => setShowOptionsDropdown(false), showOptionsDropdown);
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
return () => {
|
|
127
|
+
if (blurTimeoutRef.current)
|
|
128
|
+
clearTimeout(blurTimeoutRef.current);
|
|
129
|
+
};
|
|
130
|
+
}, []);
|
|
131
|
+
const updateValue = (newValue) => {
|
|
132
|
+
setSearchText(null);
|
|
133
|
+
onChange?.(newValue);
|
|
134
|
+
};
|
|
135
|
+
const selectOption = (option) => {
|
|
136
|
+
updateValue(option);
|
|
137
|
+
setFocusOptionIndex(null);
|
|
138
|
+
setShowOptionsDropdown(false);
|
|
139
|
+
refSearchInput.current?.blur();
|
|
140
|
+
};
|
|
141
|
+
const clearValue = (setFocus = false) => {
|
|
142
|
+
updateValue(undefined);
|
|
143
|
+
setFocusOptionIndex(null);
|
|
144
|
+
if (setFocus)
|
|
145
|
+
refSearchInput.current?.focus();
|
|
146
|
+
};
|
|
147
|
+
const onFocus = () => {
|
|
148
|
+
setShowOptionsDropdown(true);
|
|
149
|
+
};
|
|
150
|
+
const onBlur = () => {
|
|
151
|
+
if (blurTimeoutRef.current)
|
|
152
|
+
clearTimeout(blurTimeoutRef.current);
|
|
153
|
+
blurTimeoutRef.current = setTimeout(() => {
|
|
154
|
+
setSearchText(null);
|
|
155
|
+
}, 200);
|
|
156
|
+
};
|
|
157
|
+
const handleEnterKey = () => {
|
|
158
|
+
if ((!displayValue && focusOptionIndex === null) || (searchText && focusOptionIndex === null)) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const currentOptions = filteredOptions.length > 0 ? filteredOptions : options;
|
|
162
|
+
if (focusOptionIndex !== null && currentOptions[focusOptionIndex]) {
|
|
163
|
+
const selectedOption = currentOptions[focusOptionIndex];
|
|
164
|
+
updateValue(selectedOption);
|
|
165
|
+
}
|
|
166
|
+
setFocusOptionIndex(null);
|
|
167
|
+
setShowOptionsDropdown(false);
|
|
168
|
+
refSearchInput.current?.blur();
|
|
169
|
+
};
|
|
170
|
+
const handleArrowUp = () => {
|
|
171
|
+
if (!showOptionsDropdown || focusOptionIndex === 0 || focusOptionIndex === null) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
setFocusOptionIndex(focusOptionIndex - 1);
|
|
175
|
+
};
|
|
176
|
+
const handleArrowDown = () => {
|
|
177
|
+
if (!showOptionsDropdown) {
|
|
178
|
+
setFocusOptionIndex(activeOptionIndex ?? 0);
|
|
179
|
+
setShowOptionsDropdown(true);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const currentOptions = filteredOptions.length > 0 ? filteredOptions : options;
|
|
183
|
+
const nextIndex = focusOptionIndex === null ? 0 : focusOptionIndex + 1;
|
|
184
|
+
if (nextIndex < currentOptions.length) {
|
|
185
|
+
setFocusOptionIndex(nextIndex);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
const onKeyDown = (event) => {
|
|
189
|
+
switch (event.key) {
|
|
190
|
+
case 'Enter':
|
|
191
|
+
handleEnterKey();
|
|
192
|
+
break;
|
|
193
|
+
case 'ArrowUp':
|
|
194
|
+
handleArrowUp();
|
|
195
|
+
break;
|
|
196
|
+
case 'ArrowDown':
|
|
197
|
+
handleArrowDown();
|
|
198
|
+
break;
|
|
199
|
+
case 'Delete':
|
|
200
|
+
clearValue(true);
|
|
201
|
+
break;
|
|
202
|
+
case 'Escape':
|
|
203
|
+
if (!searchText) {
|
|
204
|
+
event.preventDefault();
|
|
205
|
+
setShowOptionsDropdown(false);
|
|
206
|
+
refSearchInput.current?.blur();
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
setSearchText(null);
|
|
210
|
+
setFocusOptionIndex(activeOptionIndex);
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
const onInputChange = (event) => {
|
|
216
|
+
setSearchText(event.target.value);
|
|
217
|
+
setShowOptionsDropdown(true);
|
|
218
|
+
setFocusOptionIndex(null);
|
|
219
|
+
};
|
|
220
|
+
const renderOptions = () => {
|
|
221
|
+
const currentOptions = filteredOptions.length > 0 ? filteredOptions : options;
|
|
222
|
+
if (searchText && filteredOptions.length === 0) {
|
|
223
|
+
return _jsx("div", { className: "efp-autocomplete__empty", children: noOptionsLabel });
|
|
224
|
+
}
|
|
225
|
+
// Virtualized: a plan's booth list runs to thousands of options, and rendering, laying out and
|
|
226
|
+
// compositing every one of them froze the frame the dropdown opened in for over half a second.
|
|
227
|
+
if (!scrollElement)
|
|
228
|
+
return null;
|
|
229
|
+
const context = {
|
|
230
|
+
listboxId,
|
|
231
|
+
focusIndex: focusOptionIndex,
|
|
232
|
+
activeIndex: filteredOptions.length === 0 ? activeOptionIndex : null,
|
|
233
|
+
onSelect: (index) => selectOption(currentOptions[index]),
|
|
234
|
+
};
|
|
235
|
+
return (_jsx(Suspense, { fallback: null, children: _jsx(LazyVirtuoso, { ref: virtuosoRef, customScrollParent: scrollElement, data: currentOptions, context: context, computeItemKey: (_index, option) => getOptionKey(option), itemContent: (_index, option) => getOptionLabel(option), components: { List: OptionList, Item: OptionItem }, increaseViewportBy: 200 }) }));
|
|
236
|
+
};
|
|
237
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { ref: refAutocomplete, "data-no-drag": true, className: classNames('efp-autocomplete', {
|
|
238
|
+
'is-open': showOptionsDropdown,
|
|
239
|
+
'with-clear': showOptionsDropdown && showClear,
|
|
240
|
+
}), children: [_jsxs("div", { className: "efp-autocomplete__inner", children: [_jsx("input", { type: "search", className: "efp-autocomplete__input", role: "combobox", "aria-label": ariaLabel, "aria-autocomplete": "list", "aria-expanded": showOptionsDropdown, "aria-controls": showOptionsDropdown ? listboxId : undefined, "aria-activedescendant": showOptionsDropdown && focusOptionIndex !== null
|
|
241
|
+
? getOptionId(focusOptionIndex)
|
|
242
|
+
: undefined, onChange: onInputChange, onFocus: onFocus, onBlur: onBlur, onKeyDown: onKeyDown, value: displayValue, placeholder: placeholder, ref: refSearchInput }), showClear && showOptionsDropdown && displayValue && (_jsx("button", { type: "button", className: "efp-autocomplete__clear", "aria-label": clearLabel, onMouseDown: (e) => {
|
|
243
|
+
e.preventDefault();
|
|
244
|
+
clearValue(true);
|
|
245
|
+
} }))] }), showOptionsDropdown && inline && (_jsx("div", { ref: refOptions, "data-no-drag": true, className: "efp-autocomplete-options efp-autocomplete-options--inline", style: inlineMaxHeight !== null ? { maxHeight: `${inlineMaxHeight}px` } : undefined, children: _jsx("div", { className: "efp-autocomplete-options__scroll", ref: setScrollElement, children: renderOptions() }) }))] }), showOptionsDropdown &&
|
|
246
|
+
!inline &&
|
|
247
|
+
container &&
|
|
248
|
+
createPortal(_jsx("div", { ref: refOptions, className: "efp-autocomplete-options", style: {
|
|
249
|
+
...(dropdownPosition.top !== undefined ? { top: `${dropdownPosition.top}px` } : {}),
|
|
250
|
+
...(dropdownPosition.bottom !== undefined
|
|
251
|
+
? { bottom: `${dropdownPosition.bottom}px` }
|
|
252
|
+
: {}),
|
|
253
|
+
left: `${dropdownPosition.left}px`,
|
|
254
|
+
width: `${dropdownPosition.width}px`,
|
|
255
|
+
maxHeight: `${dropdownPosition.maxHeight}px`,
|
|
256
|
+
}, children: _jsx("div", { className: "efp-autocomplete-options__scroll", ref: setScrollElement, children: renderOptions() }) }), container)] }));
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* The listbox itself; Virtuoso positions it inside the scroll parent.
|
|
260
|
+
* @param props - Virtuoso's list props, plus the autocomplete's context.
|
|
261
|
+
* @returns The `ul`.
|
|
262
|
+
*/
|
|
263
|
+
function OptionList({ context, ref, ...props }) {
|
|
264
|
+
// Virtuoso types its list element as a `div`; the listbox is a `ul`, which it handles the same.
|
|
265
|
+
return (_jsx("ul", { ...props, ref: ref, role: "listbox", id: context.listboxId }));
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* One option; Virtuoso renders only the ones in and near view.
|
|
269
|
+
* @param props - Virtuoso's item props, plus the autocomplete's context.
|
|
270
|
+
* @returns The `li`.
|
|
271
|
+
*/
|
|
272
|
+
function OptionItem({ context, item: _item, ...props }) {
|
|
273
|
+
const index = props['data-index'];
|
|
274
|
+
const isFocused = index === context.focusIndex;
|
|
275
|
+
const isActive = !isFocused && index === context.activeIndex;
|
|
276
|
+
return (_jsx("li", { ...props, id: `${context.listboxId}-option-${index}`, role: "option", "aria-selected": index === context.activeIndex, className: isFocused ? 'is-focus' : isActive ? 'is-active' : undefined, onMouseDown: (e) => e.preventDefault(), onClick: () => context.onSelect(index) }));
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Loads Virtuoso on first open rather than with the SDK's main chunk, as the floorplan's own lists
|
|
280
|
+
* do; the retry covers a chunk request lost to a flaky network.
|
|
281
|
+
* @returns The module, shaped for `lazy`.
|
|
282
|
+
*/
|
|
283
|
+
function importVirtuoso() {
|
|
284
|
+
return import('react-virtuoso')
|
|
285
|
+
.then((mod) => ({ default: mod.Virtuoso }))
|
|
286
|
+
.catch(() => new Promise((resolve) => {
|
|
287
|
+
setTimeout(() => resolve(importVirtuoso()), 3000);
|
|
288
|
+
}));
|
|
289
|
+
}
|
|
290
|
+
// Typed as the generic component it resolves to; `lazy` alone erases the data and context types.
|
|
291
|
+
const LazyVirtuoso = lazy(importVirtuoso);
|
|
292
|
+
export default Autocomplete;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Autocomplete';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import './Badge.scss';
|
|
2
|
+
import React, { type ReactNode } from 'react';
|
|
3
|
+
export type BadgeVariant = 'primary' | 'primary-light' | 'lightgray' | 'gray' | 'ghost' | 'orange' | 'location';
|
|
4
|
+
export interface BadgeProps {
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
variant?: BadgeVariant;
|
|
7
|
+
size?: 'xs' | 'md' | 'lg';
|
|
8
|
+
noMargins?: boolean;
|
|
9
|
+
rounded?: boolean;
|
|
10
|
+
inline?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const Badge: ({ children, variant, size, noMargins, rounded, inline, }: BadgeProps) => React.JSX.Element;
|
|
13
|
+
export default Badge;
|
|
14
|
+
//# sourceMappingURL=Badge.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import './Badge.scss';
|
|
4
|
+
import cn from 'classnames';
|
|
5
|
+
const Badge = ({ children, variant = 'ghost', size = 'lg', noMargins, rounded, inline, }) => {
|
|
6
|
+
return (_jsx("div", { className: cn({
|
|
7
|
+
'efp-badge': true,
|
|
8
|
+
[`efp-badge--${variant}`]: true,
|
|
9
|
+
[`efp-badge--${size}`]: true,
|
|
10
|
+
'is-no-margin': noMargins,
|
|
11
|
+
'is-rounded': rounded,
|
|
12
|
+
'is-inline': inline,
|
|
13
|
+
}), children: children }));
|
|
14
|
+
};
|
|
15
|
+
export default Badge;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Badge';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import './Button.scss';
|
|
2
|
+
import React, { type ReactNode } from 'react';
|
|
3
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'gray' | 'gray-border' | 'ghost' | 'danger';
|
|
4
|
+
export type ButtonSize = 'sm' | 'md' | 'lg';
|
|
5
|
+
export type ButtonTarget = '_self' | '_blank' | '_parent';
|
|
6
|
+
interface ButtonOwnProps {
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
inline?: boolean;
|
|
9
|
+
text?: string;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
variant?: ButtonVariant;
|
|
12
|
+
size?: ButtonSize;
|
|
13
|
+
target?: ButtonTarget;
|
|
14
|
+
ariaLabel?: string;
|
|
15
|
+
withBadge?: boolean;
|
|
16
|
+
/** Whether the button should have a round/circular shape */
|
|
17
|
+
round?: boolean;
|
|
18
|
+
}
|
|
19
|
+
type ButtonAsButton = ButtonOwnProps & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, keyof ButtonOwnProps> & {
|
|
20
|
+
link?: undefined;
|
|
21
|
+
ref?: React.Ref<HTMLButtonElement>;
|
|
22
|
+
};
|
|
23
|
+
type ButtonAsLink = ButtonOwnProps & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, keyof ButtonOwnProps> & {
|
|
24
|
+
link: string;
|
|
25
|
+
ref?: React.Ref<HTMLAnchorElement>;
|
|
26
|
+
};
|
|
27
|
+
export type ButtonProps = ButtonAsButton | ButtonAsLink;
|
|
28
|
+
declare const Button: (props: ButtonProps) => React.JSX.Element;
|
|
29
|
+
export default Button;
|
|
30
|
+
//# sourceMappingURL=Button.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import './Button.scss';
|
|
3
|
+
import cn from 'classnames';
|
|
4
|
+
// `if (props.link)` alone doesn't narrow the union for TS; this predicate does.
|
|
5
|
+
const isLinkProps = (props) => props.link != null;
|
|
6
|
+
const processLabel = (label) => {
|
|
7
|
+
const parts = label.split(/(#\d+#)/);
|
|
8
|
+
const badgeMatch = /#(\d+)#/.exec(label);
|
|
9
|
+
const badgeValue = badgeMatch ? badgeMatch[1] : null;
|
|
10
|
+
return {
|
|
11
|
+
content: parts.map((part, index) => {
|
|
12
|
+
if (/#\d+#/.exec(part)) {
|
|
13
|
+
return (_jsx("div", { className: "efp-button-badge", children: badgeValue }, index));
|
|
14
|
+
}
|
|
15
|
+
return _jsx("span", { children: part }, index);
|
|
16
|
+
}),
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
const Button = (props) => {
|
|
20
|
+
const { children, inline = false, text, disabled = false, variant = 'primary', size = 'lg', target = '_self', ariaLabel, title, withBadge = false, round, } = props;
|
|
21
|
+
const content = children ?? text;
|
|
22
|
+
const { content: processedContent } = withBadge && typeof content === 'string' ? processLabel(content) : { content };
|
|
23
|
+
const commonClassNames = cn('efp-button', `efp-button--${variant}`, `efp-button--${size}`, {
|
|
24
|
+
'efp-button--inline': inline,
|
|
25
|
+
'is-disabled': disabled,
|
|
26
|
+
'efp-button--round': round,
|
|
27
|
+
}, props.className);
|
|
28
|
+
if (isLinkProps(props)) {
|
|
29
|
+
const { link, className: _className, onClick, ...rest } = props;
|
|
30
|
+
const onKeyDown = (event) => {
|
|
31
|
+
if (disabled || event.key !== ' ')
|
|
32
|
+
return;
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
event.currentTarget.click();
|
|
35
|
+
};
|
|
36
|
+
return (_jsx("a", { ...rest, href: disabled ? undefined : link, className: commonClassNames, target: target, rel: "noopener noreferrer", onClick: disabled ? undefined : onClick, onKeyDown: onKeyDown, "aria-label": ariaLabel || undefined, title: title || ariaLabel || (typeof content === 'string' ? content : undefined), role: "button", "aria-disabled": disabled, tabIndex: disabled ? -1 : 0, children: processedContent }));
|
|
37
|
+
}
|
|
38
|
+
const { className: _className, ...rest } = props;
|
|
39
|
+
return (_jsx("button", { type: "button", ...rest, className: commonClassNames, disabled: disabled, "aria-label": ariaLabel || undefined, title: title || ariaLabel || (typeof content === 'string' ? content : undefined), children: processedContent }));
|
|
40
|
+
};
|
|
41
|
+
export default Button;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Button';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import './Checkbox.scss';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
interface CheckboxBase {
|
|
4
|
+
name?: string;
|
|
5
|
+
value: boolean;
|
|
6
|
+
indeterminate?: boolean;
|
|
7
|
+
size?: 'sm' | 'md';
|
|
8
|
+
onChange: (value: boolean) => void;
|
|
9
|
+
}
|
|
10
|
+
export type CheckboxProps = (CheckboxBase & {
|
|
11
|
+
label: string;
|
|
12
|
+
ariaLabel?: string;
|
|
13
|
+
}) | (CheckboxBase & {
|
|
14
|
+
label?: undefined;
|
|
15
|
+
ariaLabel: string;
|
|
16
|
+
});
|
|
17
|
+
declare const Checkbox: ({ name, value, label, ariaLabel, size, indeterminate, onChange, }: CheckboxProps) => React.JSX.Element;
|
|
18
|
+
export default Checkbox;
|
|
19
|
+
//# sourceMappingURL=Checkbox.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import './Checkbox.scss';
|
|
4
|
+
import classNames from 'classnames';
|
|
5
|
+
import { useEffect, useId, useRef } from 'react';
|
|
6
|
+
const Checkbox = ({ name, value, label, ariaLabel, size = 'md', indeterminate = false, onChange, }) => {
|
|
7
|
+
const id = useId();
|
|
8
|
+
const checkboxRef = useRef(null);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (checkboxRef.current) {
|
|
11
|
+
checkboxRef.current.indeterminate = indeterminate;
|
|
12
|
+
}
|
|
13
|
+
}, [indeterminate]);
|
|
14
|
+
return (_jsxs("div", { className: classNames({
|
|
15
|
+
'efp-checkbox': true,
|
|
16
|
+
[`efp-checkbox--${size}`]: true,
|
|
17
|
+
}), children: [_jsx("input", { ref: checkboxRef, type: "checkbox", id: id, name: name, checked: value, "aria-label": ariaLabel, onChange: () => onChange(!value) }), _jsx("label", { htmlFor: id, children: label })] }));
|
|
18
|
+
};
|
|
19
|
+
export default Checkbox;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Checkbox';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import './CheckboxButton.scss';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export interface CheckboxButtonProps {
|
|
4
|
+
checked: boolean;
|
|
5
|
+
label?: string;
|
|
6
|
+
ariaLabel?: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
onClick: () => void;
|
|
9
|
+
}
|
|
10
|
+
declare const CheckboxButton: ({ checked, label, ariaLabel, className, onClick }: CheckboxButtonProps) => React.JSX.Element;
|
|
11
|
+
export default CheckboxButton;
|
|
12
|
+
//# sourceMappingURL=CheckboxButton.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import './CheckboxButton.scss';
|
|
4
|
+
import cn from 'classnames';
|
|
5
|
+
import { useState } from 'react';
|
|
6
|
+
const CheckboxButton = ({ checked, label, ariaLabel, className, onClick }) => {
|
|
7
|
+
const [animateIcon, setAnimateIcon] = useState(false);
|
|
8
|
+
const handleClick = () => {
|
|
9
|
+
setAnimateIcon(true);
|
|
10
|
+
onClick();
|
|
11
|
+
setTimeout(() => {
|
|
12
|
+
setAnimateIcon(false);
|
|
13
|
+
}, 320);
|
|
14
|
+
};
|
|
15
|
+
return (_jsxs("button", { type: "button", role: "checkbox", "aria-checked": checked, "aria-label": ariaLabel ?? (label ? undefined : 'Toggle'), className: cn('efp-checkbox-button', className, { 'efp-checkbox-button--checked': checked }), onClick: handleClick, children: [_jsx("div", { className: cn('efp-checkbox-button__inner', {
|
|
16
|
+
'efp-checkbox-button__inner--animate': animateIcon,
|
|
17
|
+
}) }), label && _jsx("span", { className: "efp-checkbox-button__label", children: label })] }));
|
|
18
|
+
};
|
|
19
|
+
export default CheckboxButton;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './CheckboxButton';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import './DownloadList.scss';
|
|
2
|
+
export interface DownloadItem {
|
|
3
|
+
fileName: string;
|
|
4
|
+
path: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DownloadListProps {
|
|
7
|
+
list: DownloadItem[];
|
|
8
|
+
/** Section heading (e.g. a localized "Read More"). */
|
|
9
|
+
title: string;
|
|
10
|
+
/** Builds the per-item download link accessible name from its file name. */
|
|
11
|
+
downloadLabel: (fileName: string) => string;
|
|
12
|
+
}
|
|
13
|
+
declare function DownloadList({ list, title, downloadLabel }: DownloadListProps): import("react").JSX.Element;
|
|
14
|
+
export default DownloadList;
|
|
15
|
+
//# sourceMappingURL=DownloadList.d.ts.map
|