Skip to content
This repository was archived by the owner on Jan 16, 2026. It is now read-only.

Commit fcd8ea3

Browse files
committed
fix(react): add CSS post-processor to prefix class selectors with data-wallet-ui
This commit adds a post-processing script that prefixes all CSS class selectors with `[data-wallet-ui]` to increase their specificity and solve issues with reset styles in consumer projects. It also updates component structure to ensure the `data-wallet-ui` attribute is correctly placed on parent elements that wrap Tailwind-styled content. The post-processing approach ensures utility classes properly override preflight styles in projects that don't use Tailwind CSS, maintaining the intended appearance of our components regardless of the host application's styling environment.
1 parent 64108c6 commit fcd8ea3

File tree

4 files changed

+349
-289
lines changed

4 files changed

+349
-289
lines changed

packages/react/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
"lint": "eslint \"**/*.{js,jsx,ts,tsx}\"",
5858
"format": "prettier --write .",
5959
"typecheck": "tsc --noEmit",
60-
"generate:css": "npx @tailwindcss/cli -c ./tailwind.config.js -i ./src/input.css -o ./dist/style.css"
60+
"generate:css": "npx @tailwindcss/cli -c ./tailwind.config.js -i ./src/input.css -o ./dist/style.css && node ./scripts/post-process-css.js"
6161
},
6262
"peerDependencies": {
6363
"@txnlab/use-wallet-react": "^4.0.1",
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Post-processes the generated Tailwind CSS file to ensure utility classes
4+
* have higher specificity than preflight styles when scoped.
5+
*
6+
* This script adds [data-wallet-ui] prefix to CSS class selectors to increase
7+
* their specificity and prevent them from being overridden by preflight styles.
8+
*/
9+
10+
import fs from 'fs/promises'
11+
import path from 'path'
12+
13+
const STYLE_FILE_PATH = path.resolve('./dist/style.css')
14+
15+
// Check if a line contains a top-level class selector
16+
function isTopLevelClassSelector(line) {
17+
const trimmed = line.trim()
18+
// Skip existing prefixed lines, at-rules, and comments
19+
if (
20+
line.includes('[data-wallet-ui]') ||
21+
trimmed.startsWith('@') ||
22+
trimmed.startsWith('/*') ||
23+
trimmed.startsWith('*')
24+
) {
25+
return false
26+
}
27+
// Match a line that starts with a period followed by valid CSS class characters
28+
return /^\s*\.[a-zA-Z0-9_\-\\:]+[^\{]*\{/.test(line)
29+
}
30+
31+
async function main() {
32+
try {
33+
// Read the generated CSS file
34+
const cssContent = await fs.readFile(STYLE_FILE_PATH, 'utf8')
35+
const lines = cssContent.split('\n')
36+
37+
// Process each line
38+
const processedLines = lines.map((line) => {
39+
if (isTopLevelClassSelector(line)) {
40+
// Replace the first occurrence of a period with '[data-wallet-ui] .'
41+
return line.replace(/(\s*)\./, '$1[data-wallet-ui] .')
42+
}
43+
return line
44+
})
45+
46+
// Write the processed content back to the file
47+
await fs.writeFile(STYLE_FILE_PATH, processedLines.join('\n'))
48+
49+
console.log(
50+
`Processed CSS file to add [data-wallet-ui] prefix to class selectors in ${STYLE_FILE_PATH}`,
51+
)
52+
} catch (error) {
53+
console.error('Error processing CSS file:', error)
54+
process.exit(1)
55+
}
56+
}
57+
58+
main()

packages/react/src/components/ConnectWalletMenu.tsx

Lines changed: 72 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -120,79 +120,80 @@ export function ConnectWalletMenu({ children }: ConnectWalletMenuProps) {
120120
{trigger}
121121
<FloatingPortal id="wallet-dialog-portal">
122122
{isOpen && (
123-
<FloatingOverlay
124-
className="grid place-items-center px-4 z-50 transition-opacity duration-150 ease-in-out bg-black/30 dark:bg-black/50 data-[state=starting]:opacity-0 data-[state=exiting]:opacity-0 data-[state=entered]:opacity-100"
125-
data-state={animationState}
126-
lockScroll
127-
data-wallet-ui
128-
>
129-
<FloatingFocusManager context={context} modal={true}>
130-
<div
131-
ref={refs.setFloating}
132-
{...getFloatingProps({
133-
'aria-labelledby': labelId,
134-
'aria-describedby': descriptionId,
135-
})}
136-
data-state={animationState}
137-
className="w-full max-w-sm rounded-3xl bg-white dark:bg-[#001324] shadow-xl transform transition-all duration-150 ease-in-out data-[state=starting]:opacity-0 data-[state=starting]:scale-90 data-[state=exiting]:opacity-0 data-[state=exiting]:scale-90 data-[state=entered]:opacity-100 data-[state=entered]:scale-100"
138-
style={{
139-
marginTop: '-0.5rem',
140-
}}
141-
>
142-
{/* Header */}
143-
<div className="relative flex items-center px-6 pt-5 pb-4">
144-
<h2
145-
id={labelId}
146-
className="text-xl font-bold text-gray-900 dark:text-[#E9E9FD] wallet-custom-font"
147-
>
148-
Connect a Wallet
149-
</h2>
150-
{/* Close button */}
151-
<button
152-
onClick={() => context.onOpenChange(false)}
153-
className="absolute right-4 rounded-full bg-gray-100 dark:bg-[#192A39]/75 p-2 text-gray-500 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-[#192A39] hover:text-gray-700 dark:hover:text-[#D4D4FA]"
154-
aria-label="Close dialog"
155-
>
156-
<svg
157-
xmlns="http://www.w3.org/2000/svg"
158-
className="h-5 w-5"
159-
viewBox="0 0 20 20"
160-
fill="currentColor"
123+
<div data-wallet-ui>
124+
<FloatingOverlay
125+
className="grid place-items-center px-4 z-50 transition-opacity duration-150 ease-in-out bg-black/30 dark:bg-black/50 data-[state=starting]:opacity-0 data-[state=exiting]:opacity-0 data-[state=entered]:opacity-100"
126+
data-state={animationState}
127+
lockScroll
128+
>
129+
<FloatingFocusManager context={context} modal={true}>
130+
<div
131+
ref={refs.setFloating}
132+
{...getFloatingProps({
133+
'aria-labelledby': labelId,
134+
'aria-describedby': descriptionId,
135+
})}
136+
data-state={animationState}
137+
className="w-full max-w-sm rounded-3xl bg-white dark:bg-[#001324] shadow-xl transform transition-all duration-150 ease-in-out data-[state=starting]:opacity-0 data-[state=starting]:scale-90 data-[state=exiting]:opacity-0 data-[state=exiting]:scale-90 data-[state=entered]:opacity-100 data-[state=entered]:scale-100"
138+
style={{
139+
marginTop: '-0.5rem',
140+
}}
141+
>
142+
{/* Header */}
143+
<div className="relative flex items-center px-6 pt-5 pb-4">
144+
<h2
145+
id={labelId}
146+
className="text-xl font-bold text-gray-900 dark:text-[#E9E9FD] wallet-custom-font"
161147
>
162-
<path
163-
fillRule="evenodd"
164-
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
165-
clipRule="evenodd"
166-
/>
167-
</svg>
168-
</button>
169-
</div>
170-
171-
{/* Wallet list */}
172-
<div className="px-4 pb-3">
173-
<WalletList
174-
wallets={wallets}
175-
handleWalletClick={handleWalletClick}
176-
/>
177-
</div>
178-
179-
{/* Footer section */}
180-
<div className="px-6 py-5 border-t border-gray-200 dark:border-[#192A39] flex items-center justify-between">
181-
<span className="text-gray-600 dark:text-[#99A1A7] text-sm">
182-
Need an Algorand wallet?
183-
</span>
184-
<a
185-
href="https://algorand.co/wallets"
186-
className="text-[#2D2DF1]/80 dark:text-[#6C6CF1] font-medium text-sm hover:text-[#2D2DF1] dark:hover:text-[#8080F3]"
187-
target="_blank"
188-
rel="noopener noreferrer"
189-
>
190-
Start here →
191-
</a>
148+
Connect a Wallet
149+
</h2>
150+
{/* Close button */}
151+
<button
152+
onClick={() => context.onOpenChange(false)}
153+
className="absolute right-4 rounded-full bg-gray-100 dark:bg-[#192A39]/75 p-2 text-gray-500 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-[#192A39] hover:text-gray-700 dark:hover:text-[#D4D4FA]"
154+
aria-label="Close dialog"
155+
>
156+
<svg
157+
xmlns="http://www.w3.org/2000/svg"
158+
className="h-5 w-5"
159+
viewBox="0 0 20 20"
160+
fill="currentColor"
161+
>
162+
<path
163+
fillRule="evenodd"
164+
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
165+
clipRule="evenodd"
166+
/>
167+
</svg>
168+
</button>
169+
</div>
170+
171+
{/* Wallet list */}
172+
<div className="px-4 pb-3">
173+
<WalletList
174+
wallets={wallets}
175+
handleWalletClick={handleWalletClick}
176+
/>
177+
</div>
178+
179+
{/* Footer section */}
180+
<div className="px-6 py-5 border-t border-gray-200 dark:border-[#192A39] flex items-center justify-between">
181+
<span className="text-gray-600 dark:text-[#99A1A7] text-sm">
182+
Need an Algorand wallet?
183+
</span>
184+
<a
185+
href="https://algorand.co/wallets"
186+
className="text-[#2D2DF1]/80 dark:text-[#6C6CF1] font-medium text-sm hover:text-[#2D2DF1] dark:hover:text-[#8080F3]"
187+
target="_blank"
188+
rel="noopener noreferrer"
189+
>
190+
Start here →
191+
</a>
192+
</div>
192193
</div>
193-
</div>
194-
</FloatingFocusManager>
195-
</FloatingOverlay>
194+
</FloatingFocusManager>
195+
</FloatingOverlay>
196+
</div>
196197
)}
197198
</FloatingPortal>
198199
</>

0 commit comments

Comments
 (0)