@timmbr/ui 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +9 -0
- package/dist/components/Breadcrumb/Breadcrumb.d.ts.map +1 -0
- package/dist/components/Breadcrumb/Breadcrumb.js +32 -0
- package/dist/components/Breadcrumb/Breadcrumb.styles.d.ts +8 -0
- package/dist/components/Breadcrumb/Breadcrumb.styles.d.ts.map +1 -0
- package/dist/components/Breadcrumb/Breadcrumb.styles.js +20 -0
- package/dist/components/Breadcrumb/Breadcrumb.types.d.ts +27 -0
- package/dist/components/Breadcrumb/Breadcrumb.types.d.ts.map +1 -0
- package/dist/components/Breadcrumb/index.d.ts +4 -0
- package/dist/components/Breadcrumb/index.d.ts.map +1 -0
- package/dist/components/Chip/Chip.d.ts.map +1 -1
- package/dist/components/Chip/Chip.js +13 -3
- package/dist/components/Chip/Chip.types.d.ts +5 -0
- package/dist/components/Chip/Chip.types.d.ts.map +1 -1
- package/dist/components/Drawer/Drawer.d.ts.map +1 -1
- package/dist/components/Drawer/Drawer.js +4 -4
- package/dist/components/Drawer/Drawer.styles.d.ts +1 -0
- package/dist/components/Drawer/Drawer.styles.d.ts.map +1 -1
- package/dist/components/Drawer/Drawer.styles.js +7 -1
- package/dist/components/Drawer/Drawer.types.d.ts +2 -0
- package/dist/components/Drawer/Drawer.types.d.ts.map +1 -1
- package/dist/components/FilterChips/FilterChips.d.ts +8 -0
- package/dist/components/FilterChips/FilterChips.d.ts.map +1 -0
- package/dist/components/FilterChips/FilterChips.js +39 -0
- package/dist/components/FilterChips/FilterChips.types.d.ts +17 -0
- package/dist/components/FilterChips/FilterChips.types.d.ts.map +1 -0
- package/dist/components/FilterChips/index.d.ts +3 -0
- package/dist/components/FilterChips/index.d.ts.map +1 -0
- package/dist/components/FilterDrawer/FilterDrawer.d.ts +12 -0
- package/dist/components/FilterDrawer/FilterDrawer.d.ts.map +1 -0
- package/dist/components/FilterDrawer/FilterDrawer.js +157 -0
- package/dist/components/FilterDrawer/FilterDrawer.styles.d.ts +12 -0
- package/dist/components/FilterDrawer/FilterDrawer.styles.d.ts.map +1 -0
- package/dist/components/FilterDrawer/FilterDrawer.styles.js +30 -0
- package/dist/components/FilterDrawer/FilterDrawer.types.d.ts +28 -0
- package/dist/components/FilterDrawer/FilterDrawer.types.d.ts.map +1 -0
- package/dist/components/FilterDrawer/index.d.ts +4 -0
- package/dist/components/FilterDrawer/index.d.ts.map +1 -0
- package/dist/components/FilterPanel/FilterPanel.d.ts +33 -0
- package/dist/components/FilterPanel/FilterPanel.d.ts.map +1 -0
- package/dist/components/FilterPanel/FilterPanel.js +239 -0
- package/dist/components/FilterPanel/FilterPanel.styles.d.ts +16 -0
- package/dist/components/FilterPanel/FilterPanel.styles.d.ts.map +1 -0
- package/dist/components/FilterPanel/FilterPanel.styles.js +31 -0
- package/dist/components/FilterPanel/FilterPanel.types.d.ts +80 -0
- package/dist/components/FilterPanel/FilterPanel.types.d.ts.map +1 -0
- package/dist/components/FilterPanel/FilterPanel.types.js +3 -0
- package/dist/components/FilterPanel/index.d.ts +4 -0
- package/dist/components/FilterPanel/index.d.ts.map +1 -0
- package/dist/components/ImageUpload/ImageUpload.styles.d.ts +3 -3
- package/dist/components/MediaCard/MediaCard.d.ts.map +1 -1
- package/dist/components/MediaCard/MediaCard.js +3 -1
- package/dist/components/NavHeader/NavHeader.styles.d.ts +7 -0
- package/dist/components/NavHeader/NavHeader.styles.d.ts.map +1 -1
- package/dist/components/NavHeader/NavHeader.styles.js +20 -2
- package/dist/components/NavHeader/NavHeader.types.d.ts +49 -1
- package/dist/components/NavHeader/NavHeader.types.d.ts.map +1 -1
- package/dist/components/NavHeader/index.d.ts +3 -2
- package/dist/components/NavHeader/index.d.ts.map +1 -1
- package/dist/components/NavHeader/subcomponents/NavMobileSearchDrawer.d.ts.map +1 -1
- package/dist/components/NavHeader/subcomponents/NavMobileSearchDrawer.js +15 -33
- package/dist/components/NavHeader/subcomponents/NavSearch.d.ts.map +1 -1
- package/dist/components/NavHeader/subcomponents/NavSearch.js +37 -83
- package/dist/components/NavHeader/subcomponents/NavSearchPanel.d.ts +63 -0
- package/dist/components/NavHeader/subcomponents/NavSearchPanel.d.ts.map +1 -0
- package/dist/components/NavHeader/subcomponents/NavSearchPanel.js +289 -0
- package/dist/components/NavMenuColumns/NavMenuColumns.styles.js +1 -1
- package/dist/components/OptionPicker/OptionPicker.d.ts +10 -0
- package/dist/components/OptionPicker/OptionPicker.d.ts.map +1 -0
- package/dist/components/OptionPicker/OptionPicker.js +116 -0
- package/dist/components/OptionPicker/OptionPicker.styles.d.ts +20 -0
- package/dist/components/OptionPicker/OptionPicker.styles.d.ts.map +1 -0
- package/dist/components/OptionPicker/OptionPicker.styles.js +60 -0
- package/dist/components/OptionPicker/OptionPicker.types.d.ts +39 -0
- package/dist/components/OptionPicker/OptionPicker.types.d.ts.map +1 -0
- package/dist/components/OptionPicker/index.d.ts +4 -0
- package/dist/components/OptionPicker/index.d.ts.map +1 -0
- package/dist/components/Price/Price.styles.d.ts.map +1 -1
- package/dist/components/Price/Price.styles.js +3 -2
- package/dist/components/ProductGallery/ProductGallery.d.ts +10 -0
- package/dist/components/ProductGallery/ProductGallery.d.ts.map +1 -0
- package/dist/components/ProductGallery/ProductGallery.js +306 -0
- package/dist/components/ProductGallery/ProductGallery.styles.d.ts +32 -0
- package/dist/components/ProductGallery/ProductGallery.styles.d.ts.map +1 -0
- package/dist/components/ProductGallery/ProductGallery.styles.js +86 -0
- package/dist/components/ProductGallery/ProductGallery.types.d.ts +55 -0
- package/dist/components/ProductGallery/ProductGallery.types.d.ts.map +1 -0
- package/dist/components/ProductGallery/ProductGalleryLightbox.d.ts +20 -0
- package/dist/components/ProductGallery/ProductGalleryLightbox.d.ts.map +1 -0
- package/dist/components/ProductGallery/ProductGalleryLightbox.js +210 -0
- package/dist/components/ProductGallery/index.d.ts +4 -0
- package/dist/components/ProductGallery/index.d.ts.map +1 -0
- package/dist/components/QuantityStepper/QuantityStepper.d.ts +8 -0
- package/dist/components/QuantityStepper/QuantityStepper.d.ts.map +1 -0
- package/dist/components/QuantityStepper/QuantityStepper.js +65 -0
- package/dist/components/QuantityStepper/QuantityStepper.styles.d.ts +8 -0
- package/dist/components/QuantityStepper/QuantityStepper.styles.d.ts.map +1 -0
- package/dist/components/QuantityStepper/QuantityStepper.styles.js +24 -0
- package/dist/components/QuantityStepper/QuantityStepper.types.d.ts +20 -0
- package/dist/components/QuantityStepper/QuantityStepper.types.d.ts.map +1 -0
- package/dist/components/QuantityStepper/index.d.ts +4 -0
- package/dist/components/QuantityStepper/index.d.ts.map +1 -0
- package/dist/components/RangeSlider/RangeSlider.d.ts.map +1 -1
- package/dist/components/RangeSlider/RangeSlider.js +5 -3
- package/dist/components/RangeSlider/RangeSlider.types.d.ts +7 -0
- package/dist/components/RangeSlider/RangeSlider.types.d.ts.map +1 -1
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/Select.js +14 -1
- package/dist/components/Select/Select.types.d.ts +4 -0
- package/dist/components/Select/Select.types.d.ts.map +1 -1
- package/dist/components/Snackbar/Snackbar.d.ts +9 -0
- package/dist/components/Snackbar/Snackbar.d.ts.map +1 -0
- package/dist/components/Snackbar/Snackbar.js +108 -0
- package/dist/components/Snackbar/Snackbar.styles.d.ts +17 -0
- package/dist/components/Snackbar/Snackbar.styles.d.ts.map +1 -0
- package/dist/components/Snackbar/Snackbar.styles.js +37 -0
- package/dist/components/Snackbar/Snackbar.types.d.ts +36 -0
- package/dist/components/Snackbar/Snackbar.types.d.ts.map +1 -0
- package/dist/components/Snackbar/SnackbarHost.d.ts +4 -0
- package/dist/components/Snackbar/SnackbarHost.d.ts.map +1 -0
- package/dist/components/Snackbar/SnackbarHost.js +24 -0
- package/dist/components/Snackbar/index.d.ts +6 -0
- package/dist/components/Snackbar/index.d.ts.map +1 -0
- package/dist/components/Snackbar/snackbarStore.d.ts +42 -0
- package/dist/components/Snackbar/snackbarStore.d.ts.map +1 -0
- package/dist/components/Snackbar/snackbarStore.js +87 -0
- package/dist/components/StockMeter/StockMeter.d.ts +8 -0
- package/dist/components/StockMeter/StockMeter.d.ts.map +1 -0
- package/dist/components/StockMeter/StockMeter.js +19 -0
- package/dist/components/StockMeter/StockMeter.styles.d.ts +4 -0
- package/dist/components/StockMeter/StockMeter.styles.d.ts.map +1 -0
- package/dist/components/StockMeter/StockMeter.styles.js +7 -0
- package/dist/components/StockMeter/StockMeter.types.d.ts +10 -0
- package/dist/components/StockMeter/StockMeter.types.d.ts.map +1 -0
- package/dist/components/StockMeter/index.d.ts +4 -0
- package/dist/components/StockMeter/index.d.ts.map +1 -0
- package/dist/components/Swatch/Swatch.d.ts +11 -0
- package/dist/components/Swatch/Swatch.d.ts.map +1 -0
- package/dist/components/Swatch/Swatch.js +40 -0
- package/dist/components/Swatch/Swatch.styles.d.ts +8 -0
- package/dist/components/Swatch/Swatch.styles.d.ts.map +1 -0
- package/dist/components/Swatch/Swatch.styles.js +26 -0
- package/dist/components/Swatch/Swatch.types.d.ts +11 -0
- package/dist/components/Swatch/Swatch.types.d.ts.map +1 -0
- package/dist/components/Swatch/index.d.ts +4 -0
- package/dist/components/Swatch/index.d.ts.map +1 -0
- package/dist/components/Toast/Toast.d.ts.map +1 -1
- package/dist/components/Toast/Toast.js +49 -42
- package/dist/components/Toast/Toast.types.d.ts +7 -0
- package/dist/components/Toast/Toast.types.d.ts.map +1 -1
- package/dist/components/Toast/ToastContainer.d.ts.map +1 -1
- package/dist/components/Toast/ToastContainer.js +5 -0
- package/dist/components/Toast/toastStore.d.ts +11 -0
- package/dist/components/Toast/toastStore.d.ts.map +1 -1
- package/dist/components/Toast/toastStore.js +70 -30
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -1
- package/dist/providers/TimmbrConfigProvider.d.ts.map +1 -1
- package/dist/providers/TimmbrConfigProvider.js +5 -9
- package/package.json +5 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterDrawer.types.d.ts","sourceRoot":"","sources":["../../../src/components/FilterDrawer/FilterDrawer.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAE1G,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,CAAC;CAC/C;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,6FAA6F;IAC7F,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,6EAA6E;IAC7E,KAAK,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,SAAS,CAAC,CAAC;IACvD,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,qEAAqE;IACrE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACrC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FilterDrawer/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type FilterGroup, type FilterOption, type FilterOptionListProps, type FilterPanelLabels, type FilterPanelProps, type FilterPriceConfig } from './FilterPanel.types';
|
|
3
|
+
export declare const DEFAULT_FILTER_LABELS: FilterPanelLabels;
|
|
4
|
+
/** An option is unavailable when picking it would show nothing (and it isn't picked already). */
|
|
5
|
+
export declare const isOptionDisabled: (option: FilterOption) => boolean;
|
|
6
|
+
/**
|
|
7
|
+
* The options of one group as checkboxes (with a colour dot for swatch groups) and counts.
|
|
8
|
+
* Long groups show the first `limit` options plus every selected one behind "Show more", and
|
|
9
|
+
* very long groups get a search box. Options that would show nothing are disabled, not hidden,
|
|
10
|
+
* so the list doesn't jump as filters change.
|
|
11
|
+
*/
|
|
12
|
+
export declare function FilterOptionList({ group, onToggle, limit, searchThreshold, labels: labelOverrides, className, }: FilterOptionListProps): React.JSX.Element;
|
|
13
|
+
/** Yes/no groups as switches: "Fast Delivery (12)". */
|
|
14
|
+
export declare function FilterToggleRow({ group, onToggle, }: {
|
|
15
|
+
group: FilterGroup;
|
|
16
|
+
onToggle: (key: string, value: string) => void;
|
|
17
|
+
}): React.JSX.Element | null;
|
|
18
|
+
/** The price slider with Apply/Reset; the slider value is local until Apply. */
|
|
19
|
+
export declare function FilterPriceSlider({ price, labels: labelOverrides, onValueChange, showActions, }: {
|
|
20
|
+
price: FilterPriceConfig;
|
|
21
|
+
labels?: Partial<FilterPanelLabels>;
|
|
22
|
+
/** Called while dragging (the drawer stages the value instead of using Apply). */
|
|
23
|
+
onValueChange?: (min: number, max: number) => void;
|
|
24
|
+
showActions?: boolean;
|
|
25
|
+
}): React.JSX.Element;
|
|
26
|
+
/**
|
|
27
|
+
* Filter sidebar for a listing (Figma PLP): yes/no toggles first, then a price slider and
|
|
28
|
+
* collapsible groups of checkbox or swatch options with result counts. Purely presentational:
|
|
29
|
+
* selections come in through `groups`, changes go out through `onToggle` — the page decides
|
|
30
|
+
* when to apply them (see the listing-state helpers in @timmbr/utils).
|
|
31
|
+
*/
|
|
32
|
+
export declare const FilterPanel: React.ForwardRefExoticComponent<FilterPanelProps & React.RefAttributes<HTMLDivElement>>;
|
|
33
|
+
//# sourceMappingURL=FilterPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterPanel.d.ts","sourceRoot":"","sources":["../../../src/components/FilterPanel/FilterPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAsB/B,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACvB,MAAM,qBAAqB,CAAC;AAE7B,eAAO,MAAM,qBAAqB,EAAE,iBAYnC,CAAC;AAEF,iGAAiG;AACjG,eAAO,MAAM,gBAAgB,GAAI,QAAQ,YAAY,YAAgE,CAAC;AActH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,KAAS,EACT,eAAoB,EACpB,MAAM,EAAE,cAAc,EACtB,SAAS,GACV,EAAE,qBAAqB,qBA2DvB;AAED,uDAAuD;AACvD,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAChD,4BAmBA;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,MAAM,EAAE,cAAc,EACtB,aAAa,EACb,WAAkB,GACnB,EAAE;IACD,KAAK,EAAE,iBAAiB,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACpC,kFAAkF;IAClF,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,qBAkCA;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,yFA2FvB,CAAC"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Search } from '@timmbr/icons';
|
|
5
|
+
import { cn } from '@timmbr/utils';
|
|
6
|
+
import { filterOptionRowVariants, filterLinkButtonVariants, filterPanelTitleVariants, filterPanelHeaderVariants, filterToggleListVariants, filterSectionTriggerVariants, filterSectionContentVariants, filterPanelBodyVariants, filterPanelVariants, filterOptionCountVariants, filterOptionLabelVariants } from './FilterPanel.styles.js';
|
|
7
|
+
import { PRICE_GROUP_KEY } from './FilterPanel.types.js';
|
|
8
|
+
import { Input } from '../Input/Input.js';
|
|
9
|
+
import { Checkbox } from '../Checkbox/Checkbox.js';
|
|
10
|
+
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '../Accordion/Accordion.js';
|
|
11
|
+
import { RangeSlider } from '../RangeSlider/RangeSlider.js';
|
|
12
|
+
import { Switch } from '../Switch/Switch.js';
|
|
13
|
+
import { Swatch } from '../Swatch/Swatch.js';
|
|
14
|
+
|
|
15
|
+
const DEFAULT_FILTER_LABELS = {
|
|
16
|
+
title: "Filters",
|
|
17
|
+
price: "Price range",
|
|
18
|
+
apply: "Apply",
|
|
19
|
+
reset: "Reset",
|
|
20
|
+
clear: "Clear",
|
|
21
|
+
showLess: "Show less",
|
|
22
|
+
showMore: (hidden) => `Show more (${hidden})`,
|
|
23
|
+
searchPlaceholder: (group) => `Search ${group.toLowerCase()}`,
|
|
24
|
+
noMatches: "No matches",
|
|
25
|
+
thumbMin: "Minimum price",
|
|
26
|
+
thumbMax: "Maximum price"
|
|
27
|
+
};
|
|
28
|
+
const isOptionDisabled = (option) => option.disabled ?? (option.count === 0 && !option.selected);
|
|
29
|
+
const selectedCount = (group) => group.options.filter((o) => o.selected).length;
|
|
30
|
+
function OptionLabel({ option, display }) {
|
|
31
|
+
return /* @__PURE__ */ jsxs("span", { className: filterOptionLabelVariants(), children: [
|
|
32
|
+
display === "swatch" && option.swatch && /* @__PURE__ */ jsx(Swatch, { color: option.swatch, size: "sm" }),
|
|
33
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: option.label }),
|
|
34
|
+
option.count !== void 0 && /* @__PURE__ */ jsxs("span", { className: filterOptionCountVariants(), children: [
|
|
35
|
+
"(",
|
|
36
|
+
option.count,
|
|
37
|
+
")"
|
|
38
|
+
] })
|
|
39
|
+
] });
|
|
40
|
+
}
|
|
41
|
+
function FilterOptionList({
|
|
42
|
+
group,
|
|
43
|
+
onToggle,
|
|
44
|
+
limit = 5,
|
|
45
|
+
searchThreshold = 15,
|
|
46
|
+
labels: labelOverrides,
|
|
47
|
+
className
|
|
48
|
+
}) {
|
|
49
|
+
const labels = { ...DEFAULT_FILTER_LABELS, ...labelOverrides };
|
|
50
|
+
const [expanded, setExpanded] = React.useState(false);
|
|
51
|
+
const [query, setQuery] = React.useState("");
|
|
52
|
+
const searchable = group.options.length > searchThreshold;
|
|
53
|
+
const needle = query.trim().toLowerCase();
|
|
54
|
+
const ordered = [
|
|
55
|
+
...group.options.filter((o) => !isOptionDisabled(o)),
|
|
56
|
+
...group.options.filter((o) => isOptionDisabled(o))
|
|
57
|
+
];
|
|
58
|
+
const matching = needle ? ordered.filter((o) => o.label.toLowerCase().includes(needle)) : ordered;
|
|
59
|
+
const visible = expanded || needle ? matching : matching.filter((o, i) => i < limit || o.selected);
|
|
60
|
+
const hidden = matching.length - visible.length;
|
|
61
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3 pb-4", className), "data-slot": "filter-option-list", children: [
|
|
62
|
+
searchable && /* @__PURE__ */ jsx(
|
|
63
|
+
Input,
|
|
64
|
+
{
|
|
65
|
+
size: "sm",
|
|
66
|
+
type: "search",
|
|
67
|
+
value: query,
|
|
68
|
+
onChange: (e) => setQuery(e.target.value),
|
|
69
|
+
placeholder: labels.searchPlaceholder(group.label),
|
|
70
|
+
"aria-label": labels.searchPlaceholder(group.label),
|
|
71
|
+
leftAdornment: /* @__PURE__ */ jsx(Search, { className: "size-4" })
|
|
72
|
+
}
|
|
73
|
+
),
|
|
74
|
+
/* @__PURE__ */ jsxs("ul", { className: "flex flex-col gap-3", children: [
|
|
75
|
+
visible.map((option) => {
|
|
76
|
+
const disabled = isOptionDisabled(option);
|
|
77
|
+
return /* @__PURE__ */ jsx("li", { className: filterOptionRowVariants({ disabled }), children: /* @__PURE__ */ jsx(
|
|
78
|
+
Checkbox,
|
|
79
|
+
{
|
|
80
|
+
size: "sm",
|
|
81
|
+
checked: !!option.selected,
|
|
82
|
+
disabled,
|
|
83
|
+
onCheckedChange: () => onToggle(group.key, option.value),
|
|
84
|
+
label: /* @__PURE__ */ jsx(OptionLabel, { option, display: group.display })
|
|
85
|
+
}
|
|
86
|
+
) }, option.value);
|
|
87
|
+
}),
|
|
88
|
+
visible.length === 0 && /* @__PURE__ */ jsx("li", { className: "text-body-3 text-grey-500", children: labels.noMatches })
|
|
89
|
+
] }),
|
|
90
|
+
!needle && (hidden > 0 || expanded) && matching.length > limit && /* @__PURE__ */ jsx(
|
|
91
|
+
"button",
|
|
92
|
+
{
|
|
93
|
+
type: "button",
|
|
94
|
+
className: filterLinkButtonVariants(),
|
|
95
|
+
"aria-expanded": expanded,
|
|
96
|
+
onClick: () => setExpanded((e) => !e),
|
|
97
|
+
children: expanded ? labels.showLess : labels.showMore(hidden)
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
] });
|
|
101
|
+
}
|
|
102
|
+
function FilterToggleRow({
|
|
103
|
+
group,
|
|
104
|
+
onToggle
|
|
105
|
+
}) {
|
|
106
|
+
const option = group.options[0];
|
|
107
|
+
if (!option) return null;
|
|
108
|
+
const disabled = isOptionDisabled(option);
|
|
109
|
+
return /* @__PURE__ */ jsx(
|
|
110
|
+
Switch,
|
|
111
|
+
{
|
|
112
|
+
size: "sm",
|
|
113
|
+
checked: !!option.selected,
|
|
114
|
+
disabled,
|
|
115
|
+
onCheckedChange: () => onToggle(group.key, option.value),
|
|
116
|
+
containerClassName: cn(disabled && "opacity-50"),
|
|
117
|
+
label: /* @__PURE__ */ jsxs("span", { className: filterOptionLabelVariants(), children: [
|
|
118
|
+
group.label,
|
|
119
|
+
option.count !== void 0 && /* @__PURE__ */ jsxs("span", { className: filterOptionCountVariants(), children: [
|
|
120
|
+
"(",
|
|
121
|
+
option.count,
|
|
122
|
+
")"
|
|
123
|
+
] })
|
|
124
|
+
] })
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
function FilterPriceSlider({
|
|
129
|
+
price,
|
|
130
|
+
labels: labelOverrides,
|
|
131
|
+
onValueChange,
|
|
132
|
+
showActions = true
|
|
133
|
+
}) {
|
|
134
|
+
const labels = { ...DEFAULT_FILTER_LABELS, ...labelOverrides };
|
|
135
|
+
const applied = price.value ?? [price.min, price.max];
|
|
136
|
+
const atBounds = (v) => v[0] <= price.min && v[1] >= price.max;
|
|
137
|
+
const appliedKey = `${applied[0]}-${applied[1]}-${price.min}-${price.max}-${price.resetKey ?? ""}`;
|
|
138
|
+
const [local, setLocal] = React.useState({
|
|
139
|
+
key: appliedKey,
|
|
140
|
+
value: applied
|
|
141
|
+
});
|
|
142
|
+
const draft = local.key === appliedKey ? local.value : applied;
|
|
143
|
+
const setDraft = (value) => setLocal({ key: appliedKey, value });
|
|
144
|
+
return /* @__PURE__ */ jsx(
|
|
145
|
+
RangeSlider,
|
|
146
|
+
{
|
|
147
|
+
min: price.min,
|
|
148
|
+
max: price.max,
|
|
149
|
+
step: price.step,
|
|
150
|
+
value: draft,
|
|
151
|
+
formatValue: price.format,
|
|
152
|
+
showActions,
|
|
153
|
+
applyLabel: labels.apply,
|
|
154
|
+
resetLabel: labels.reset,
|
|
155
|
+
thumbLabels: [labels.thumbMin, labels.thumbMax],
|
|
156
|
+
resetDisabled: atBounds(applied) && atBounds(draft),
|
|
157
|
+
onValueChange: (values) => {
|
|
158
|
+
setDraft(values);
|
|
159
|
+
onValueChange?.(values[0], values[1]);
|
|
160
|
+
},
|
|
161
|
+
onApply: (values) => price.onApply(values[0], values[1]),
|
|
162
|
+
onReset: () => price.onReset()
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
const FilterPanel = React.forwardRef(
|
|
167
|
+
({
|
|
168
|
+
groups,
|
|
169
|
+
onToggle,
|
|
170
|
+
onClearGroup,
|
|
171
|
+
price,
|
|
172
|
+
defaultOpen,
|
|
173
|
+
optionLimit,
|
|
174
|
+
searchThreshold,
|
|
175
|
+
labels: labelOverrides,
|
|
176
|
+
headerAction,
|
|
177
|
+
className
|
|
178
|
+
}, ref) => {
|
|
179
|
+
const labels = { ...DEFAULT_FILTER_LABELS, ...labelOverrides };
|
|
180
|
+
const toggles = groups.filter((g) => g.display === "toggle");
|
|
181
|
+
const sections = groups.filter((g) => g.display !== "toggle");
|
|
182
|
+
const showPrice = !!price && price.max - price.min >= price.step && price.step > 0;
|
|
183
|
+
const [initialOpen] = React.useState(
|
|
184
|
+
() => defaultOpen ?? [PRICE_GROUP_KEY, ...sections.slice(0, 3).map((g) => g.key)]
|
|
185
|
+
);
|
|
186
|
+
return /* @__PURE__ */ jsxs("div", { ref, "data-slot": "filter-panel", className: cn(filterPanelVariants(), className), children: [
|
|
187
|
+
/* @__PURE__ */ jsxs("div", { className: filterPanelHeaderVariants(), children: [
|
|
188
|
+
/* @__PURE__ */ jsx("h2", { className: filterPanelTitleVariants(), children: labels.title }),
|
|
189
|
+
headerAction
|
|
190
|
+
] }),
|
|
191
|
+
/* @__PURE__ */ jsxs("div", { "data-slot": "filter-panel-body", className: filterPanelBodyVariants(), children: [
|
|
192
|
+
toggles.length > 0 && /* @__PURE__ */ jsx("div", { className: filterToggleListVariants(), children: toggles.map((group) => /* @__PURE__ */ jsx(FilterToggleRow, { group, onToggle }, group.key)) }),
|
|
193
|
+
/* @__PURE__ */ jsxs(Accordion, { type: "multiple", defaultValue: initialOpen, className: "border-t border-grey-200", children: [
|
|
194
|
+
showPrice && price && /* @__PURE__ */ jsxs(AccordionItem, { value: PRICE_GROUP_KEY, className: "border-grey-200", children: [
|
|
195
|
+
/* @__PURE__ */ jsx(AccordionTrigger, { className: filterSectionTriggerVariants(), children: labels.price }),
|
|
196
|
+
/* @__PURE__ */ jsx(AccordionContent, { className: filterSectionContentVariants(), children: /* @__PURE__ */ jsx("div", { className: "pb-4", children: /* @__PURE__ */ jsx(FilterPriceSlider, { price, labels }) }) })
|
|
197
|
+
] }),
|
|
198
|
+
sections.map((group) => {
|
|
199
|
+
const count = selectedCount(group);
|
|
200
|
+
return /* @__PURE__ */ jsxs(AccordionItem, { value: group.key, className: "border-grey-200", children: [
|
|
201
|
+
/* @__PURE__ */ jsx(AccordionTrigger, { className: filterSectionTriggerVariants(), children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
|
|
202
|
+
group.label,
|
|
203
|
+
count > 0 && /* @__PURE__ */ jsxs("span", { className: "text-primary", children: [
|
|
204
|
+
"(",
|
|
205
|
+
count,
|
|
206
|
+
")"
|
|
207
|
+
] })
|
|
208
|
+
] }) }),
|
|
209
|
+
/* @__PURE__ */ jsxs(AccordionContent, { className: filterSectionContentVariants(), children: [
|
|
210
|
+
count > 0 && onClearGroup && /* @__PURE__ */ jsx(
|
|
211
|
+
"button",
|
|
212
|
+
{
|
|
213
|
+
type: "button",
|
|
214
|
+
className: cn(filterLinkButtonVariants(), "mb-3"),
|
|
215
|
+
onClick: () => onClearGroup(group.key),
|
|
216
|
+
children: labels.clear
|
|
217
|
+
}
|
|
218
|
+
),
|
|
219
|
+
/* @__PURE__ */ jsx(
|
|
220
|
+
FilterOptionList,
|
|
221
|
+
{
|
|
222
|
+
group,
|
|
223
|
+
onToggle,
|
|
224
|
+
limit: optionLimit,
|
|
225
|
+
searchThreshold,
|
|
226
|
+
labels
|
|
227
|
+
}
|
|
228
|
+
)
|
|
229
|
+
] })
|
|
230
|
+
] }, group.key);
|
|
231
|
+
})
|
|
232
|
+
] })
|
|
233
|
+
] })
|
|
234
|
+
] });
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
FilterPanel.displayName = "FilterPanel";
|
|
238
|
+
|
|
239
|
+
export { DEFAULT_FILTER_LABELS, FilterOptionList, FilterPanel, FilterPriceSlider, FilterToggleRow, isOptionDisabled };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Card: white surface, light shadow (Figma PLP filter sidebar). */
|
|
2
|
+
export declare const filterPanelVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
3
|
+
export declare const filterPanelHeaderVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
4
|
+
/** Everything below the header; scrolls inside the card when the card has a max height. */
|
|
5
|
+
export declare const filterPanelBodyVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
6
|
+
export declare const filterPanelTitleVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
7
|
+
export declare const filterToggleListVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
8
|
+
export declare const filterSectionTriggerVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
9
|
+
export declare const filterSectionContentVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
10
|
+
export declare const filterOptionRowVariants: (props?: ({
|
|
11
|
+
disabled?: boolean | null | undefined;
|
|
12
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
13
|
+
export declare const filterOptionLabelVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
14
|
+
export declare const filterOptionCountVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
15
|
+
export declare const filterLinkButtonVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
16
|
+
//# sourceMappingURL=FilterPanel.styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterPanel.styles.d.ts","sourceRoot":"","sources":["../../../src/components/FilterPanel/FilterPanel.styles.ts"],"names":[],"mappings":"AAEA,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,oFAAiF,CAAC;AAElH,eAAO,MAAM,yBAAyB,oFAErC,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,uBAAuB,oFAEnC,CAAC;AAEF,eAAO,MAAM,wBAAwB,oFAA6D,CAAC;AAEnG,eAAO,MAAM,wBAAwB,oFAAuC,CAAC;AAE7E,eAAO,MAAM,4BAA4B,oFAExC,CAAC;AAEF,eAAO,MAAM,4BAA4B,oFAAc,CAAC;AAExD,eAAO,MAAM,uBAAuB;;8EAQlC,CAAC;AAEH,eAAO,MAAM,yBAAyB,oFAA0E,CAAC;AAEjH,eAAO,MAAM,yBAAyB,oFAAmC,CAAC;AAE1E,eAAO,MAAM,wBAAwB,oFAEpC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { cva } from 'class-variance-authority';
|
|
2
|
+
|
|
3
|
+
const filterPanelVariants = cva("flex flex-col overflow-hidden rounded-sm bg-grey-50 font-sans shadow-md");
|
|
4
|
+
const filterPanelHeaderVariants = cva(
|
|
5
|
+
"flex shrink-0 items-center justify-between gap-2 border-b border-grey-100 px-5 py-4"
|
|
6
|
+
);
|
|
7
|
+
const filterPanelBodyVariants = cva(
|
|
8
|
+
"min-h-0 flex-1 overflow-y-auto [scrollbar-gutter:stable] [scrollbar-width:thin]"
|
|
9
|
+
);
|
|
10
|
+
const filterPanelTitleVariants = cva("text-body-1 font-medium tracking-wide text-grey-950");
|
|
11
|
+
const filterToggleListVariants = cva("flex flex-col gap-4 px-5 py-4");
|
|
12
|
+
const filterSectionTriggerVariants = cva(
|
|
13
|
+
"px-4 py-4 text-body-3 font-medium uppercase tracking-wider text-grey-950 hover:no-underline"
|
|
14
|
+
);
|
|
15
|
+
const filterSectionContentVariants = cva("px-4");
|
|
16
|
+
const filterOptionRowVariants = cva("min-w-0", {
|
|
17
|
+
variants: {
|
|
18
|
+
disabled: {
|
|
19
|
+
true: "opacity-50",
|
|
20
|
+
false: ""
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: { disabled: false }
|
|
24
|
+
});
|
|
25
|
+
const filterOptionLabelVariants = cva("inline-flex min-w-0 items-center gap-2 text-body-2 text-grey-700");
|
|
26
|
+
const filterOptionCountVariants = cva("text-body-3 text-grey-500");
|
|
27
|
+
const filterLinkButtonVariants = cva(
|
|
28
|
+
"self-start rounded-sm text-body-3 font-semibold text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50"
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
export { filterLinkButtonVariants, filterOptionCountVariants, filterOptionLabelVariants, filterOptionRowVariants, filterPanelBodyVariants, filterPanelHeaderVariants, filterPanelTitleVariants, filterPanelVariants, filterSectionContentVariants, filterSectionTriggerVariants, filterToggleListVariants };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
/** How a group's options are shown. */
|
|
3
|
+
export type FilterGroupDisplay = 'checkbox' | 'swatch' | 'toggle';
|
|
4
|
+
export interface FilterOption {
|
|
5
|
+
/** Value sent back in `onToggle` (e.g. a URL slug). */
|
|
6
|
+
value: string;
|
|
7
|
+
label: string;
|
|
8
|
+
/** Matching results if this option were picked; shown as "(12)". */
|
|
9
|
+
count?: number;
|
|
10
|
+
selected?: boolean;
|
|
11
|
+
/** Defaults to true when `count` is 0 and the option isn't selected. */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** Colour for swatch groups. */
|
|
14
|
+
swatch?: string | null;
|
|
15
|
+
}
|
|
16
|
+
export interface FilterGroup {
|
|
17
|
+
key: string;
|
|
18
|
+
label: string;
|
|
19
|
+
display: FilterGroupDisplay;
|
|
20
|
+
options: FilterOption[];
|
|
21
|
+
}
|
|
22
|
+
export interface FilterPriceConfig {
|
|
23
|
+
/** Slider bounds and step. */
|
|
24
|
+
min: number;
|
|
25
|
+
max: number;
|
|
26
|
+
step: number;
|
|
27
|
+
/** The applied range (the slider starts here). */
|
|
28
|
+
value?: [number, number];
|
|
29
|
+
/** Shown on the readouts, e.g. (v) => `₹${v}`. */
|
|
30
|
+
format?: (value: number) => string;
|
|
31
|
+
onApply: (min: number, max: number) => void;
|
|
32
|
+
onReset: () => void;
|
|
33
|
+
/**
|
|
34
|
+
* Changes whenever the slider should drop an un-applied drag and show `value` again, e.g.
|
|
35
|
+
* the URL of the applied listing (so "Clear all" also resets the slider).
|
|
36
|
+
*/
|
|
37
|
+
resetKey?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface FilterPanelLabels {
|
|
40
|
+
title: string;
|
|
41
|
+
price: string;
|
|
42
|
+
apply: string;
|
|
43
|
+
reset: string;
|
|
44
|
+
clear: string;
|
|
45
|
+
showLess: string;
|
|
46
|
+
showMore: (hidden: number) => string;
|
|
47
|
+
searchPlaceholder: (groupLabel: string) => string;
|
|
48
|
+
noMatches: string;
|
|
49
|
+
thumbMin: string;
|
|
50
|
+
thumbMax: string;
|
|
51
|
+
}
|
|
52
|
+
export interface FilterOptionListProps {
|
|
53
|
+
group: FilterGroup;
|
|
54
|
+
onToggle: (key: string, value: string) => void;
|
|
55
|
+
/** Options shown before "Show more" (selected ones always show). @default 5 */
|
|
56
|
+
limit?: number;
|
|
57
|
+
/** Groups with more options than this get a search box. @default 15 */
|
|
58
|
+
searchThreshold?: number;
|
|
59
|
+
labels?: Partial<FilterPanelLabels>;
|
|
60
|
+
className?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface FilterPanelProps {
|
|
63
|
+
groups: FilterGroup[];
|
|
64
|
+
onToggle: (key: string, value: string) => void;
|
|
65
|
+
/** Clears one group; adds a "Clear" link to groups with a selection. */
|
|
66
|
+
onClearGroup?: (key: string) => void;
|
|
67
|
+
/** Price slider, shown first when the range is wider than one step. */
|
|
68
|
+
price?: FilterPriceConfig;
|
|
69
|
+
/** Groups open at first ("price" is the slider). Default: price and the first three groups. */
|
|
70
|
+
defaultOpen?: string[];
|
|
71
|
+
optionLimit?: number;
|
|
72
|
+
searchThreshold?: number;
|
|
73
|
+
labels?: Partial<FilterPanelLabels>;
|
|
74
|
+
/** Right side of the header, e.g. a "Clear all" button. */
|
|
75
|
+
headerAction?: React.ReactNode;
|
|
76
|
+
className?: string;
|
|
77
|
+
}
|
|
78
|
+
/** Group key used by the panel and drawer for the price slider. */
|
|
79
|
+
export declare const PRICE_GROUP_KEY = "price";
|
|
80
|
+
//# sourceMappingURL=FilterPanel.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterPanel.types.d.ts","sourceRoot":"","sources":["../../../src/components/FilterPanel/FilterPanel.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FilterPanel/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC"}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { type VariantProps } from 'class-variance-authority';
|
|
2
2
|
export declare const imageUploadZoneVariants: (props?: ({
|
|
3
|
-
aspectRatio?: "
|
|
3
|
+
aspectRatio?: "auto" | "video" | "square" | "wide" | null | undefined;
|
|
4
4
|
size?: "default" | "compact" | null | undefined;
|
|
5
5
|
isDragging?: boolean | null | undefined;
|
|
6
6
|
isError?: boolean | null | undefined;
|
|
7
7
|
isDisabled?: boolean | null | undefined;
|
|
8
8
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
9
9
|
export declare const imagePreviewContainerVariants: (props?: ({
|
|
10
|
-
aspectRatio?: "
|
|
10
|
+
aspectRatio?: "auto" | "video" | "square" | "wide" | null | undefined;
|
|
11
11
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
12
12
|
export declare const thumbnailCardVariants: (props?: ({
|
|
13
|
-
aspectRatio?: "
|
|
13
|
+
aspectRatio?: "auto" | "video" | "square" | "wide" | null | undefined;
|
|
14
14
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
15
15
|
export type ImageUploadZoneVariants = VariantProps<typeof imageUploadZoneVariants>;
|
|
16
16
|
export type ImagePreviewContainerVariants = VariantProps<typeof imagePreviewContainerVariants>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaCard.d.ts","sourceRoot":"","sources":["../../../src/components/MediaCard/MediaCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAsB,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAc5E;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"MediaCard.d.ts","sourceRoot":"","sources":["../../../src/components/MediaCard/MediaCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAsB,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAc5E;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,oFAkJrB,CAAC"}
|
|
@@ -113,7 +113,9 @@ const MediaCard = React.forwardRef(
|
|
|
113
113
|
]
|
|
114
114
|
}
|
|
115
115
|
),
|
|
116
|
-
footer &&
|
|
116
|
+
footer && // mt-auto: pinned to the card's bottom, so footers line up across a grid row even when
|
|
117
|
+
// titles or prices wrap differently.
|
|
118
|
+
/* @__PURE__ */ jsx("div", { className: "relative z-10 mt-auto flex flex-wrap items-center gap-2 pt-2", "data-slot": "media-card-footer", children: footer })
|
|
117
119
|
] })
|
|
118
120
|
]
|
|
119
121
|
}
|
|
@@ -34,7 +34,14 @@ export declare const megaMenuCardVariants: (props?: import("class-variance-autho
|
|
|
34
34
|
/**
|
|
35
35
|
* Search popover suggestions card styles.
|
|
36
36
|
*/
|
|
37
|
+
/** Right-aligned under the input and wider than it, so product suggestions have room. */
|
|
37
38
|
export declare const searchPopoverCardVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
39
|
+
/** A row of the search panel (recent search, suggested product, "see all"). */
|
|
40
|
+
export declare const searchPanelOptionVariants: (props?: ({
|
|
41
|
+
active?: boolean | null | undefined;
|
|
42
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
43
|
+
export declare const searchPanelSectionTitleVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
44
|
+
export declare const searchPanelTextButtonVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
38
45
|
/**
|
|
39
46
|
* Overflow action menu dropdown popover container.
|
|
40
47
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NavHeader.styles.d.ts","sourceRoot":"","sources":["../../../src/components/NavHeader/NavHeader.styles.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,mBAAmB,oFAE/B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB;;8EAa7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B;;8EAiBtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;8EAkBjC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB;;8EAa7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,oFAEhC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,yBAAyB,oFAErC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,6BAA6B,oFAEzC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B;;8EAatC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,oFAEnC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;8EAkBjC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,6BAA6B,oFAEzC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,oFAEtC,CAAC"}
|
|
1
|
+
{"version":3,"file":"NavHeader.styles.d.ts","sourceRoot":"","sources":["../../../src/components/NavHeader/NavHeader.styles.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,mBAAmB,oFAE/B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB;;8EAa7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B;;8EAiBtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;8EAkBjC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB;;8EAa7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,oFAEhC,CAAC;AAEF;;GAEG;AACH,yFAAyF;AACzF,eAAO,MAAM,yBAAyB,oFAErC,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,yBAAyB;;8EAWrC,CAAC;AAEF,eAAO,MAAM,+BAA+B,oFAE3C,CAAC;AAEF,eAAO,MAAM,6BAA6B,oFAEzC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,6BAA6B,oFAEzC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B;;8EAatC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,oFAEnC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;8EAkBjC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,6BAA6B,oFAEzC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,oFAEtC,CAAC"}
|
|
@@ -72,7 +72,25 @@ const megaMenuCardVariants = cva(
|
|
|
72
72
|
"w-full max-w-[1216px] mx-auto bg-grey-50 border border-grey-200/80 shadow-2xl rounded-b-xl z-50 overflow-hidden"
|
|
73
73
|
);
|
|
74
74
|
const searchPopoverCardVariants = cva(
|
|
75
|
-
"absolute top-full
|
|
75
|
+
"absolute top-full right-0 mt-2 w-[min(26rem,calc(100vw-2rem))] max-h-[min(32rem,calc(100dvh-8rem))] overflow-y-auto bg-grey-50 border border-grey-200 shadow-2xl rounded-2xl p-3 sm:p-4 z-50 text-left"
|
|
76
|
+
);
|
|
77
|
+
const searchPanelOptionVariants = cva(
|
|
78
|
+
"flex w-full cursor-pointer items-center gap-3 rounded-lg px-2 py-2 text-left transition-colors",
|
|
79
|
+
{
|
|
80
|
+
variants: {
|
|
81
|
+
active: {
|
|
82
|
+
true: "bg-grey-100",
|
|
83
|
+
false: "hover:bg-grey-100"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
defaultVariants: { active: false }
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
const searchPanelSectionTitleVariants = cva(
|
|
90
|
+
"px-2 text-caption font-semibold uppercase tracking-wider text-grey-500"
|
|
91
|
+
);
|
|
92
|
+
const searchPanelTextButtonVariants = cva(
|
|
93
|
+
"rounded-sm px-2 text-body-3 font-semibold text-grey-700 underline underline-offset-4 hover:text-grey-950 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
76
94
|
);
|
|
77
95
|
const actionOverflowPopoverVariants = cva(
|
|
78
96
|
"absolute top-full right-0 mt-3 w-60 bg-grey-50 border border-border-warm shadow-2xl rounded-2xl p-2 z-50 text-left overflow-hidden divide-y divide-grey-100"
|
|
@@ -120,4 +138,4 @@ const mobileSearchDrawerVariants = cva(
|
|
|
120
138
|
"fixed inset-0 z-[9999] h-[100dvh] w-screen bg-[var(--color-bg-2,#F7F1E6)] flex flex-col overflow-hidden"
|
|
121
139
|
);
|
|
122
140
|
|
|
123
|
-
export { actionOverflowItemVariants, actionOverflowPopoverVariants, megaMenuCardVariants, mobileSearchDrawerVariants, mobileTabContentPanelVariants, mobileTabItemVariants, mobileTabSliderVariants, navActionVariants, navHeaderContainerVariants, navHeaderItemVariants, navHeaderVariants, offerBannerVariants, searchPopoverCardVariants };
|
|
141
|
+
export { actionOverflowItemVariants, actionOverflowPopoverVariants, megaMenuCardVariants, mobileSearchDrawerVariants, mobileTabContentPanelVariants, mobileTabItemVariants, mobileTabSliderVariants, navActionVariants, navHeaderContainerVariants, navHeaderItemVariants, navHeaderVariants, offerBannerVariants, searchPanelOptionVariants, searchPanelSectionTitleVariants, searchPanelTextButtonVariants, searchPopoverCardVariants };
|
|
@@ -82,6 +82,38 @@ export interface PopularSearchTag {
|
|
|
82
82
|
zone?: string;
|
|
83
83
|
onClick?: (tag: PopularSearchTag) => void;
|
|
84
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* A product (or any destination) suggested under the search box while typing.
|
|
87
|
+
*/
|
|
88
|
+
export interface NavSearchResult {
|
|
89
|
+
id: string;
|
|
90
|
+
href: string;
|
|
91
|
+
title: string;
|
|
92
|
+
/** Secondary line, e.g. the brand. */
|
|
93
|
+
subtitle?: string;
|
|
94
|
+
/** Preformatted price, e.g. "₹24,999". */
|
|
95
|
+
price?: string;
|
|
96
|
+
imageUrl?: string;
|
|
97
|
+
imageAlt?: string;
|
|
98
|
+
/** The link leaves this zone: rendered as a plain <a> (full page load) instead of `linkComponent`. */
|
|
99
|
+
crossZone?: boolean;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Suggestions shown while typing (once the query reaches `minQueryLength`).
|
|
103
|
+
*/
|
|
104
|
+
export interface NavSearchResults {
|
|
105
|
+
items: NavSearchResult[];
|
|
106
|
+
/** A request for the current query is in flight (shows placeholders when there are no items yet). */
|
|
107
|
+
loading?: boolean;
|
|
108
|
+
/** Section title. Defaults to "Products". */
|
|
109
|
+
title?: string;
|
|
110
|
+
/** Shown when the query has no matches. Defaults to "No products match". */
|
|
111
|
+
emptyLabel?: string;
|
|
112
|
+
/** Label of the last row, which submits the query. Defaults to `See all results for "…"`. */
|
|
113
|
+
viewAllLabel?: (query: string) => string;
|
|
114
|
+
/** Characters needed before suggestions show (recent searches show below it). Defaults to 2. */
|
|
115
|
+
minQueryLength?: number;
|
|
116
|
+
}
|
|
85
117
|
/**
|
|
86
118
|
* Configuration for the expandable search bar and its suggestions popover.
|
|
87
119
|
*/
|
|
@@ -108,12 +140,28 @@ export interface NavSearchConfig {
|
|
|
108
140
|
popoverContent?: React.ReactNode;
|
|
109
141
|
/** Custom suggestions node rendered inside search drawer */
|
|
110
142
|
suggestions?: React.ReactNode;
|
|
111
|
-
/**
|
|
143
|
+
/** Popular search chips, shown while the input is empty. None by default. */
|
|
112
144
|
popularSearches?: PopularSearchTag[];
|
|
113
145
|
/** Title for the popular searches section. Defaults to "Popular Searches" */
|
|
114
146
|
popularSearchesTitle?: string;
|
|
115
147
|
/** Callback fired when user clicks a popular search chip */
|
|
116
148
|
onPopularSearchClick?: (tag: PopularSearchTag) => void;
|
|
149
|
+
/** The shopper's recent searches (newest first), shown while the input is empty. Picking one submits it. */
|
|
150
|
+
recentSearches?: string[];
|
|
151
|
+
/** Title for the recent searches section. Defaults to "Recent searches" */
|
|
152
|
+
recentSearchesTitle?: string;
|
|
153
|
+
/** Removes one recent search (shows a remove button per row; Delete key on the active row). */
|
|
154
|
+
onRecentSearchRemove?: (query: string) => void;
|
|
155
|
+
/** Clears all recent searches (shows a "Clear" button). */
|
|
156
|
+
onClearRecentSearches?: () => void;
|
|
157
|
+
/** Label of the clear button. Defaults to "Clear" */
|
|
158
|
+
clearRecentSearchesLabel?: string;
|
|
159
|
+
/** Accessible label of a row's remove button. Defaults to `Remove "…" from recent searches` */
|
|
160
|
+
removeRecentSearchLabel?: (query: string) => string;
|
|
161
|
+
/** Suggestions while typing (e.g. matching products). */
|
|
162
|
+
results?: NavSearchResults;
|
|
163
|
+
/** Called when a suggested result is picked (before navigation). */
|
|
164
|
+
onResultSelect?: (result: NavSearchResult) => void;
|
|
117
165
|
/** Custom aria-label for search input */
|
|
118
166
|
ariaLabel?: string;
|
|
119
167
|
/** Display mode for search on mobile/tablet viewports (< 1024px). Defaults to 'bar' */
|