Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/strict-regions-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@wso2/oxygen-ui': patch
'@wso2/oxygen-ui-charts-react': patch
'@wso2/oxygen-ui-icons-react': patch
---

Fix dropdown menu background issue and WSO2 logo icon
11 changes: 3 additions & 8 deletions packages/oxygen-ui-icons-react/icons/wso2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions packages/oxygen-ui-icons-react/scripts/build-icons.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ export declare const ${svgName}: LucideIcon;
fs.writeFileSync(path.join(distDir, "index.ts"), indexContent);
fs.writeFileSync(path.join(distDir, "index.d.ts"), indexTypesContent);

// eslint-disable-next-line no-undef
console.log(`✅ Generated ${files.length} icons in dist/icons`);
// eslint-disable-next-line no-undef
console.log(`✨ All icons + lucide-react are exported from ${PACKAGE_NAME}`);
}

Expand Down
24 changes: 18 additions & 6 deletions packages/oxygen-ui/src/styles/Themes/AcrylicBaseTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ const AcrylicBaseTheme = extendTheme(OxygenThemeBase, {
},
background: {
default: '#f5f5f5',
paper: '#ffffffe1',
acrylic: '#ffffff4a',
paper: '#ffffffc5',
acrylic: '#ffffff40', // More transparent version for Paper and Card components
},
text: {
primary: '#40404B',
Expand All @@ -61,8 +61,8 @@ const AcrylicBaseTheme = extendTheme(OxygenThemeBase, {
},
background: {
default: '#000000',
paper: '#000000b8',
acrylic: '#00000045', // More transparent version for Paper and Card components
paper: '#000000c5',
acrylic: '#00000040', // More transparent version for Paper and Card components
},
text: {
primary: '#efefef',
Expand Down Expand Up @@ -202,8 +202,20 @@ const AcrylicBaseTheme = extendTheme(OxygenThemeBase, {
MuiPopover: {
styleOverrides: {
paper: ({ theme }: { theme: OxygenTheme }) => ({
background: theme.vars!.palette.background.paper,
opacity: 0.95,
backgroundColor: theme.vars!.palette.background.paper,
WebkitBackdropFilter: theme.blur.medium,
backdropFilter: theme.blur.medium,
backgroundImage: 'none',
})
}
},
MuiAutocomplete: {
styleOverrides: {
paper: ({ theme }: { theme: OxygenTheme }) => ({
backgroundColor: theme.vars!.palette.background.paper,
WebkitBackdropFilter: theme.blur.medium,
backdropFilter: theme.blur.medium,
backgroundImage: 'none',
})
}
},
Expand Down
13 changes: 10 additions & 3 deletions samples/oxygen-ui-test-app/src/layouts/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ import {
Button,
useAppShell,
useNotifications,
version as OXYGEN_UI_VERSION
version as OXYGEN_UI_VERSION,
Box
} from '@wso2/oxygen-ui'
import { useState, useEffect, type JSX, useCallback } from 'react'
import { useNavigate, useLocation, Outlet, Link as NavigateLink, useParams } from 'react-router'
Expand All @@ -62,6 +63,7 @@ import {
Users,
User as UserIcon,
LogOut,
WSO2,
} from '@wso2/oxygen-ui-icons-react';
import { mockNotifications, mockOrganizations, mockProjects, mockUser } from '../mock-data';
import type { Organization, Project } from '../mock-data/types';
Expand Down Expand Up @@ -178,7 +180,7 @@ export default function AppLayout(): JSX.Element {
<Header.Toggle />
<Header.Brand>
<Header.BrandLogo><Logo /></Header.BrandLogo>
<Header.BrandTitle>Developer</Header.BrandTitle>
<Header.BrandTitle>Console</Header.BrandTitle>
</Header.Brand>
<Header.Switchers showDivider={false}>
{isOrganization && (
Expand Down Expand Up @@ -400,7 +402,12 @@ export default function AppLayout(): JSX.Element {

<AppShell.Footer>
<Footer>
<Footer.Copyright>© {new Date().getFullYear()} WSO2 LLC. All rights reserved.</Footer.Copyright>
<Footer.Copyright>
© {new Date().getFullYear()} |
<Box sx={{ verticalAlign: 'middle', mt: .2, mx: .5, display: 'inline-block' }}>
<WSO2 size={12} />
</Box>
WSO2 LLC.</Footer.Copyright>
<Footer.Divider />
<Footer.Version>oxygen-ui-v{OXYGEN_UI_VERSION}</Footer.Version>
<Footer.Link href="#terms">Terms & Conditions</Footer.Link>
Expand Down
38 changes: 25 additions & 13 deletions samples/oxygen-ui-test-app/src/pages/SettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
Avatar,
ThemeSwitcher,
PageContent,
Autocomplete,
} from '@wso2/oxygen-ui'
import {
Save,
Expand Down Expand Up @@ -296,20 +297,31 @@ export default function SettingsPage(): JSX.Element {

<FormControl>
<FormLabel>Language</FormLabel>
<Select
value={appearanceSettings.language}
onChange={(e) => {
setAppearanceSettings({ ...appearanceSettings, language: e.target.value })
handleChange()
<Autocomplete
value={{ value: appearanceSettings.language, label: {
en: 'English',
es: 'Spanish',
fr: 'French',
de: 'German',
ja: 'Japanese',
zh: 'Chinese'
}[appearanceSettings.language] || 'English' }}
onChange={(_, newValue) => {
if (newValue) {
setAppearanceSettings({ ...appearanceSettings, language: newValue.value })
handleChange()
}
}}
>
<MenuItem value="en">English</MenuItem>
<MenuItem value="es">Spanish</MenuItem>
<MenuItem value="fr">French</MenuItem>
<MenuItem value="de">German</MenuItem>
<MenuItem value="ja">Japanese</MenuItem>
<MenuItem value="zh">Chinese</MenuItem>
</Select>
options={[
{ value: 'en', label: 'English' },
{ value: 'es', label: 'Spanish' },
{ value: 'fr', label: 'French' },
{ value: 'de', label: 'German' },
{ value: 'ja', label: 'Japanese' },
{ value: 'zh', label: 'Chinese' }
]}
renderInput={(params) => <TextField {...params} />}
/>
Comment on lines +300 to +324
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -A35 -B5 '^\s*<Autocomplete' samples/oxygen-ui-test-app/src/pages/SettingsPage.tsx
rg -n 'isOptionEqualToValue' samples/oxygen-ui-test-app/src/pages/SettingsPage.tsx

Repository: wso2/oxygen-ui

Length of output: 2009


🌐 Web query:

Material-UI Autocomplete isOptionEqualToValue object options required

💡 Result:

When Autocomplete options are objects, MUI’s default equality check is basically reference equality (option === value). If your controlled value comes from elsewhere (API, form state, re-created objects), it won’t be the same object instance as the one in options, so MUI can’t “match” it and may warn: “The value provided to Autocomplete is invalid…”. MUI recommends providing isOptionEqualToValue in this case. [1]

Use a stable key (typically an id) and also provide getOptionLabel:

<Autocomplete
  options={users}
  value={selectedUser}          // should be a user object or null
  getOptionLabel={(o) => o.name ?? ""}   // must return a string
  isOptionEqualToValue={(option, value) => option.id === value.id}
  onChange={(_, v) => setSelectedUser(v)}
  renderInput={(params) => <TextField {...params} label="User" />}
/>

Notes:

  • For “no selection”, set value={null} (not "") to avoid the invalid-value warning. [2]
  • If you intend values that don’t exist in options, consider freeSolo. [1]

Sources: MUI Autocomplete docs [1], Stack Overflow discussion of the invalid-value warning and using null [2].


🏁 Script executed:

#!/bin/bash
# Check if getOptionLabel is used anywhere in this component
rg -n -B2 -A2 'getOptionLabel' samples/oxygen-ui-test-app/src/pages/SettingsPage.tsx

# Check the component structure to see if there are other similar Autocomplete instances
rg -n 'Autocomplete' samples/oxygen-ui-test-app/src/pages/SettingsPage.tsx

Repository: wso2/oxygen-ui

Length of output: 114


Add isOptionEqualToValue and extract language options to prevent unstable value matching.

The value object is recreated on every render (inline object literal), and options array is also recreated on every render (inline array literal). Without isOptionEqualToValue, MUI's default reference equality check (===) will fail to match the value to any option, causing invalid-value warnings and unstable selection behavior.

Extract LANGUAGE_OPTIONS to a constant outside the component or render scope, find the matching option object for the controlled value, and provide isOptionEqualToValue to enable proper equality comparison:

Proposed fix
+const LANGUAGE_OPTIONS = [
+  { value: 'en', label: 'English' },
+  { value: 'es', label: 'Spanish' },
+  { value: 'fr', label: 'French' },
+  { value: 'de', label: 'German' },
+  { value: 'ja', label: 'Japanese' },
+  { value: 'zh', label: 'Chinese' },
+]

...
-                    <Autocomplete
-                      value={{ value: appearanceSettings.language, label: {
-                        en: 'English',
-                        es: 'Spanish',
-                        fr: 'French',
-                        de: 'German',
-                        ja: 'Japanese',
-                        zh: 'Chinese'
-                      }[appearanceSettings.language] || 'English' }}
+                    <Autocomplete
+                      value={
+                        LANGUAGE_OPTIONS.find((opt) => opt.value === appearanceSettings.language)
+                        ?? LANGUAGE_OPTIONS[0]
+                      }
+                      isOptionEqualToValue={(option, value) => option.value === value.value}
                       onChange={(_, newValue) => {
-                        if (newValue) {
-                          setAppearanceSettings({ ...appearanceSettings, language: newValue.value })
-                          handleChange()
-                        }
+                        if (!newValue) return
+                        setAppearanceSettings({ ...appearanceSettings, language: newValue.value })
+                        handleChange()
                       }}
-                      options={[
-                        { value: 'en', label: 'English' },
-                        { value: 'es', label: 'Spanish' },
-                        { value: 'fr', label: 'French' },
-                        { value: 'de', label: 'German' },
-                        { value: 'ja', label: 'Japanese' },
-                        { value: 'zh', label: 'Chinese' }
-                      ]}
+                      options={LANGUAGE_OPTIONS}
                       renderInput={(params) => <TextField {...params} />}
                     />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@samples/oxygen-ui-test-app/src/pages/SettingsPage.tsx` around lines 300 -
324, Extract the options array into a top-level constant (e.g.,
LANGUAGE_OPTIONS) and use it for the Autocomplete's options prop; compute the
controlled value by finding the matching option object from LANGUAGE_OPTIONS
using appearanceSettings.language rather than creating an inline object; and add
an isOptionEqualToValue prop (e.g., (option, value) => option.value ===
value.value) to the Autocomplete so MUI can correctly match the selected value,
then keep the existing onChange to call setAppearanceSettings and handleChange.

</FormControl>

<FormControl>
Expand Down
Loading