Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 820cdcc

Browse files
authored
Scroll up on search and improved empty state handling (#456)
- Added a new CSS class for empty feature cells to improve styling. - Updated the FeaturesTable component to display a message when no features match the search query, enhancing user experience. - Introduced a ref for the dialog content to enable scrolling to the top when a search is performed. https://github.com/user-attachments/assets/7b37372b-e573-48de-ae07-6cdcff741ad3
1 parent fc91bb4 commit 820cdcc

File tree

6 files changed

+66
-9
lines changed

6 files changed

+66
-9
lines changed

packages/browser-sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bucketco/browser-sdk",
3-
"version": "3.3.1",
3+
"version": "3.3.2",
44
"packageManager": "[email protected]",
55
"license": "MIT",
66
"repository": {

packages/browser-sdk/src/toolbar/Features.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@
6363
}
6464
}
6565

66+
.feature-empty-cell {
67+
width: 100%;
68+
color: var(--gray500);
69+
padding: 6px 0;
70+
}
71+
6672
.feature-name-cell {
6773
white-space: nowrap;
6874
overflow: hidden;

packages/browser-sdk/src/toolbar/Features.tsx

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,42 @@ export function FeaturesTable({
1919
isOpen: boolean;
2020
setIsEnabledOverride: (key: string, isEnabled: boolean | null) => void;
2121
}) {
22+
const hasFeatures = features.length > 0;
23+
const hasShownFeatures = features.some((feature) =>
24+
feature.key
25+
.toLocaleLowerCase()
26+
.includes(searchQuery?.toLocaleLowerCase() ?? ""),
27+
);
28+
29+
// List features that match the search query first then alphabetically
2230
const searchedFeatures =
2331
searchQuery === null
2432
? features
25-
: [...features].sort((a, _b) => (a.key.includes(searchQuery) ? -1 : 1));
33+
: [...features].sort((a, b) => {
34+
const aMatches = a.key.includes(searchQuery);
35+
const bMatches = b.key.includes(searchQuery);
36+
37+
// If both match or both don't match, sort alphabetically
38+
if (aMatches === bMatches) {
39+
return a.key.localeCompare(b.key);
40+
}
41+
42+
// Otherwise, matching features come first
43+
return aMatches ? -1 : 1;
44+
});
2645

27-
if (searchedFeatures.length === 0) {
28-
return <div style={{ color: "var(--gray500)" }}>No features found</div>;
29-
}
3046
return (
3147
<table class="features-table" style={{ "--n": searchedFeatures.length }}>
3248
<tbody>
49+
{(!hasFeatures || !hasShownFeatures) && (
50+
<tr>
51+
<td class="feature-empty-cell" colSpan={3}>
52+
No features{" "}
53+
{!hasShownFeatures ? `matching "${searchQuery} "` : ""}
54+
found
55+
</td>
56+
</tr>
57+
)}
3358
{searchedFeatures.map((feature, index) => (
3459
<FeatureRow
3560
key={feature.key}

packages/browser-sdk/src/toolbar/Toolbar.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export default function Toolbar({
3737
position: ToolbarPosition;
3838
}) {
3939
const toggleToolbarRef = useRef<HTMLDivElement>(null);
40+
const dialogContentRef = useRef<HTMLDivElement>(null);
4041
const [features, setFeatures] = useState<Feature[]>([]);
4142

4243
const updateFeatures = useCallback(() => {
@@ -67,6 +68,7 @@ export default function Toolbar({
6768
const [search, setSearch] = useState<string | null>(null);
6869
const onSearch = (val: string) => {
6970
setSearch(val === "" ? null : val);
71+
dialogContentRef.current?.scrollTo({ top: 0 });
7072
};
7173

7274
const sortedFeatures = [...features].sort((a, b) =>
@@ -102,7 +104,7 @@ export default function Toolbar({
102104
<DialogHeader>
103105
<FeatureSearch onSearch={onSearch} />
104106
</DialogHeader>
105-
<DialogContent>
107+
<DialogContent innerRef={dialogContentRef}>
106108
<FeaturesTable
107109
appBaseUrl={appBaseUrl}
108110
features={sortedFeatures}

packages/browser-sdk/src/ui/Dialog.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,16 +257,28 @@ function DialogArrow({
257257

258258
export function DialogHeader({
259259
children,
260+
innerRef,
260261
}: {
261262
children: preact.ComponentChildren;
263+
innerRef?: Ref<HTMLElement>;
262264
}) {
263-
return <header class="dialog-header">{children}</header>;
265+
return (
266+
<header ref={innerRef} class="dialog-header">
267+
{children}
268+
</header>
269+
);
264270
}
265271

266272
export function DialogContent({
267273
children,
274+
innerRef,
268275
}: {
269276
children: preact.ComponentChildren;
277+
innerRef?: Ref<HTMLDivElement>;
270278
}) {
271-
return <div class="dialog-content">{children}</div>;
279+
return (
280+
<div ref={innerRef} class="dialog-content">
281+
{children}
282+
</div>
283+
);
272284
}

yarn.lock

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,19 @@ __metadata:
683683
languageName: node
684684
linkType: hard
685685

686-
"@bucketco/browser-sdk@npm:3.3.1, @bucketco/browser-sdk@workspace:packages/browser-sdk":
686+
"@bucketco/browser-sdk@npm:3.3.1":
687+
version: 3.3.1
688+
resolution: "@bucketco/browser-sdk@npm:3.3.1"
689+
dependencies:
690+
"@floating-ui/dom": "npm:^1.6.8"
691+
canonical-json: "npm:^0.0.4"
692+
js-cookie: "npm:^3.0.5"
693+
preact: "npm:^10.22.1"
694+
checksum: 10c0/30bd1fa0f084c7eee0a22f917bfe488667243013711787bc36c9befa0d3aa27a4aed6f0576416a098b3d3d64ff1cf873587022d4d9c07198e11d4f81f31380de
695+
languageName: node
696+
linkType: hard
697+
698+
"@bucketco/browser-sdk@workspace:packages/browser-sdk":
687699
version: 0.0.0-use.local
688700
resolution: "@bucketco/browser-sdk@workspace:packages/browser-sdk"
689701
dependencies:

0 commit comments

Comments
 (0)