@edgeandnode/eds-react 1.0.0 → 1.0.2
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 +21 -4
- package/dist/EDSContext.d.ts +3 -0
- package/dist/EDSContext.d.ts.map +1 -1
- package/dist/EDSContext.js +7 -0
- package/dist/EDSContext.js.map +1 -1
- package/dist/EDSProvider.d.ts +1 -1
- package/dist/EDSProvider.d.ts.map +1 -1
- package/dist/EDSProvider.js +15 -8
- package/dist/EDSProvider.js.map +1 -1
- package/dist/components/Avatar.d.ts.map +1 -1
- package/dist/components/Avatar.js +3 -2
- package/dist/components/Avatar.js.map +1 -1
- package/dist/components/Breadcrumbs.parts.d.ts +4 -3
- package/dist/components/Breadcrumbs.parts.d.ts.map +1 -1
- package/dist/components/Breadcrumbs.parts.js +15 -14
- package/dist/components/Breadcrumbs.parts.js.map +1 -1
- package/dist/components/Button.d.ts.map +1 -1
- package/dist/components/Button.js +3 -2
- package/dist/components/Button.js.map +1 -1
- package/dist/components/CodeBlock.parts.d.ts.map +1 -1
- package/dist/components/CodeBlock.parts.js +16 -20
- package/dist/components/CodeBlock.parts.js.map +1 -1
- package/dist/components/CopyButton.d.ts.map +1 -1
- package/dist/components/CopyButton.js +3 -2
- package/dist/components/CopyButton.js.map +1 -1
- package/dist/components/Icon.d.ts.map +1 -1
- package/dist/components/Icon.js +3 -3
- package/dist/components/Icon.js.map +1 -1
- package/dist/components/LocalTheme.d.ts +16 -0
- package/dist/components/LocalTheme.d.ts.map +1 -0
- package/dist/components/LocalTheme.js +22 -0
- package/dist/components/LocalTheme.js.map +1 -0
- package/dist/components/Menu.parts.d.ts.map +1 -1
- package/dist/components/Menu.parts.js +6 -4
- package/dist/components/Menu.parts.js.map +1 -1
- package/dist/components/Modal.parts.d.ts.map +1 -1
- package/dist/components/Modal.parts.js +21 -10
- package/dist/components/Modal.parts.js.map +1 -1
- package/dist/components/SegmentedControl.parts.d.ts.map +1 -1
- package/dist/components/SegmentedControl.parts.js +3 -2
- package/dist/components/SegmentedControl.parts.js.map +1 -1
- package/dist/components/Select.parts.d.ts +4 -4
- package/dist/components/Select.parts.d.ts.map +1 -1
- package/dist/components/Select.parts.js +2 -1
- package/dist/components/Select.parts.js.map +1 -1
- package/dist/components/TabSet.parts.d.ts.map +1 -1
- package/dist/components/TabSet.parts.js +3 -2
- package/dist/components/TabSet.parts.js.map +1 -1
- package/dist/components/Table.parts.d.ts.map +1 -1
- package/dist/components/Table.parts.js +3 -4
- package/dist/components/Table.parts.js.map +1 -1
- package/dist/components/ThemeSwitcher.js +2 -2
- package/dist/components/ThemeSwitcher.js.map +1 -1
- package/dist/components/Tooltip.parts.js +2 -2
- package/dist/components/Tooltip.parts.js.map +1 -1
- package/dist/components/base/Addon.d.ts.map +1 -1
- package/dist/components/base/Addon.js +2 -4
- package/dist/components/base/Addon.js.map +1 -1
- package/dist/components/base/ButtonOrLink.parts.d.ts.map +1 -1
- package/dist/components/base/ButtonOrLink.parts.js +2 -1
- package/dist/components/base/ButtonOrLink.parts.js.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/index.js.map +1 -1
- package/dist/hooks/useCSSProp.js +1 -1
- package/dist/hooks/useCSSProp.js.map +1 -1
- package/dist/hooks/useEDS.d.ts +16 -1
- package/dist/hooks/useEDS.d.ts.map +1 -1
- package/dist/hooks/useEDS.js +18 -2
- package/dist/hooks/useEDS.js.map +1 -1
- package/dist/hooks/useStyleObserver.d.ts.map +1 -1
- package/dist/hooks/useStyleObserver.js +2 -1
- package/dist/hooks/useStyleObserver.js.map +1 -1
- package/dist/icons/CalendarDynamicIcon.d.ts.map +1 -1
- package/dist/icons/CalendarDynamicIcon.js +3 -1
- package/dist/icons/CalendarDynamicIcon.js.map +1 -1
- package/dist/utils/getReactNodeKey.d.ts.map +1 -1
- package/dist/utils/getReactNodeKey.js +31 -13
- package/dist/utils/getReactNodeKey.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/internal/getTooltipProps.d.ts +9 -0
- package/dist/utils/internal/getTooltipProps.d.ts.map +1 -0
- package/dist/utils/internal/getTooltipProps.js +18 -0
- package/dist/utils/internal/getTooltipProps.js.map +1 -0
- package/dist/utils/internal/index.d.ts +4 -0
- package/dist/utils/internal/index.d.ts.map +1 -0
- package/dist/utils/internal/index.js +4 -0
- package/dist/utils/internal/index.js.map +1 -0
- package/dist/utils/internal/resolveLazy.d.ts +29 -0
- package/dist/utils/internal/resolveLazy.d.ts.map +1 -0
- package/dist/utils/internal/resolveLazy.js +40 -0
- package/dist/utils/internal/resolveLazy.js.map +1 -0
- package/dist/utils/internal/styleScheduler.d.ts.map +1 -0
- package/dist/utils/internal/styleScheduler.js.map +1 -0
- package/dist/utils/isComponentType.d.ts +9 -0
- package/dist/utils/isComponentType.d.ts.map +1 -0
- package/dist/utils/isComponentType.js +22 -0
- package/dist/utils/isComponentType.js.map +1 -0
- package/dist/utils/isReactNode.d.ts +7 -0
- package/dist/utils/isReactNode.d.ts.map +1 -1
- package/dist/utils/isReactNode.js +11 -0
- package/dist/utils/isReactNode.js.map +1 -1
- package/dist/utils/reactNodeToString.d.ts +3 -0
- package/dist/utils/reactNodeToString.d.ts.map +1 -1
- package/dist/utils/reactNodeToString.js +6 -0
- package/dist/utils/reactNodeToString.js.map +1 -1
- package/dist/utils/styleObserver.js +1 -1
- package/dist/utils/trimReactNode.d.ts +3 -0
- package/dist/utils/trimReactNode.d.ts.map +1 -1
- package/dist/utils/trimReactNode.js +6 -0
- package/dist/utils/trimReactNode.js.map +1 -1
- package/package.json +9 -8
- package/scripts/update-skill.cjs +18 -5
- package/skill/SKILL.md +17 -10
- package/skill/references/tokens.md +26 -20
- package/src/EDSContext.ts +9 -0
- package/src/EDSProvider.tsx +34 -9
- package/src/components/Avatar.tsx +3 -2
- package/src/components/Breadcrumbs.parts.tsx +31 -15
- package/src/components/Button.tsx +3 -2
- package/src/components/CodeBlock.parts.tsx +20 -24
- package/src/components/CopyButton.tsx +3 -2
- package/src/components/Icon.tsx +3 -9
- package/src/components/LocalTheme.tsx +39 -0
- package/src/components/Menu.parts.tsx +5 -3
- package/src/components/Modal.parts.tsx +20 -10
- package/src/components/SegmentedControl.parts.tsx +3 -8
- package/src/components/Select.parts.tsx +6 -5
- package/src/components/TabSet.parts.tsx +3 -5
- package/src/components/Table.parts.tsx +3 -3
- package/src/components/ThemeSwitcher.tsx +2 -2
- package/src/components/Tooltip.parts.tsx +2 -2
- package/src/components/base/Addon.tsx +3 -4
- package/src/components/base/ButtonOrLink.parts.tsx +2 -1
- package/src/components/index.ts +1 -0
- package/src/hooks/useCSSProp.ts +1 -1
- package/src/hooks/useEDS.ts +18 -2
- package/src/hooks/useStyleObserver.ts +2 -1
- package/src/icons/CalendarDynamicIcon.tsx +1 -0
- package/src/utils/getReactNodeKey.ts +30 -14
- package/src/utils/index.ts +1 -1
- package/src/utils/internal/getTooltipProps.ts +25 -0
- package/src/utils/internal/index.ts +3 -0
- package/src/utils/internal/resolveLazy.ts +44 -0
- package/src/utils/isComponentType.ts +27 -0
- package/src/utils/isReactNode.ts +11 -0
- package/src/utils/reactNodeToString.ts +7 -0
- package/src/utils/styleObserver.ts +1 -1
- package/src/utils/trimReactNode.tsx +7 -0
- package/dist/utils/styleScheduler.d.ts.map +0 -1
- package/dist/utils/styleScheduler.js.map +0 -1
- package/src/__snapshots__/compiled.css +0 -22525
- package/styles/tailwind.storybook.css +0 -19
- /package/dist/utils/{styleScheduler.d.ts → internal/styleScheduler.d.ts} +0 -0
- /package/dist/utils/{styleScheduler.js → internal/styleScheduler.js} +0 -0
- /package/src/utils/{styleScheduler.ts → internal/styleScheduler.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edgeandnode/eds-react",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "React components for
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "React components for the Edge Design System",
|
|
5
5
|
"author": "Edge & Node and contributors",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -35,8 +35,9 @@
|
|
|
35
35
|
"src",
|
|
36
36
|
"!src/**/*.test.*",
|
|
37
37
|
"!src/**/*.stories.*",
|
|
38
|
+
"!src/**/__snapshots__",
|
|
39
|
+
"!styles/tailwind.storybook.css",
|
|
38
40
|
"skill",
|
|
39
|
-
"!skill/.benchmark",
|
|
40
41
|
"scripts/update-skill.cjs"
|
|
41
42
|
],
|
|
42
43
|
"peerDependencies": {
|
|
@@ -48,14 +49,14 @@
|
|
|
48
49
|
"dependencies": {
|
|
49
50
|
"@base-ui/react": "^1.8.0",
|
|
50
51
|
"@base-ui/utils": "^0.4.0",
|
|
51
|
-
"@edgeandnode/eds-css": "1.0.
|
|
52
|
-
"@edgeandnode/eds-icons": "1.0.
|
|
53
|
-
"@edgeandnode/eds-utils": "1.0.
|
|
52
|
+
"@edgeandnode/eds-css": "1.0.2",
|
|
53
|
+
"@edgeandnode/eds-icons": "1.0.2",
|
|
54
|
+
"@edgeandnode/eds-utils": "1.0.2",
|
|
54
55
|
"@react-aria/utils": "^3.34.1",
|
|
55
56
|
"@react-hookz/web": "^26.1.0",
|
|
56
57
|
"@ver0/deep-equal": "^2.0.1",
|
|
57
58
|
"escape-string-regexp": "^5.0.0",
|
|
58
|
-
"motion": "^13.4.
|
|
59
|
+
"motion": "^13.4.5",
|
|
59
60
|
"react-aria": "^3.52.1",
|
|
60
61
|
"react-keyed-flatten-children": "^5.1.3",
|
|
61
62
|
"react-markdown": "^10.1.0",
|
|
@@ -77,7 +78,7 @@
|
|
|
77
78
|
"@tailwindcss/cli": "^4.3.3",
|
|
78
79
|
"@tailwindcss/postcss": "^4.3.3",
|
|
79
80
|
"@tailwindcss/vite": "^4.3.3",
|
|
80
|
-
"@types/node": "^26.6.
|
|
81
|
+
"@types/node": "^26.6.3",
|
|
81
82
|
"@types/react": "^19.3.0",
|
|
82
83
|
"@types/react-dom": "^19.3.0",
|
|
83
84
|
"@types/react-is": "^19.3.0",
|
package/scripts/update-skill.cjs
CHANGED
|
@@ -14,6 +14,7 @@ const {
|
|
|
14
14
|
mkdirSync,
|
|
15
15
|
copyFileSync,
|
|
16
16
|
unlinkSync,
|
|
17
|
+
rmSync,
|
|
17
18
|
statSync,
|
|
18
19
|
} = require('fs')
|
|
19
20
|
const { join, dirname, relative } = require('path')
|
|
@@ -87,14 +88,11 @@ function compareSemver(a, b) {
|
|
|
87
88
|
return 0
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
/**
|
|
91
|
-
* Recursively copy a directory, overwriting existing files. Only copies files that are included in
|
|
92
|
-
* the published package (skips dotdirs).
|
|
93
|
-
*/
|
|
91
|
+
/** Recursively copy a directory, overwriting existing files. */
|
|
94
92
|
function copyDir(src, dest) {
|
|
95
93
|
mkdirSync(dest, { recursive: true })
|
|
96
94
|
for (const entry of readdirSync(src, { withFileTypes: true })) {
|
|
97
|
-
// Skip dotdirs (e.g.
|
|
95
|
+
// Skip dotfiles and dotdirs (e.g. `.DS_Store` when the package is linked from a workspace)
|
|
98
96
|
if (entry.name.startsWith('.')) continue
|
|
99
97
|
|
|
100
98
|
const srcPath = join(src, entry.name)
|
|
@@ -145,6 +143,21 @@ for (const targetDir of foundDirs) {
|
|
|
145
143
|
// If no version field, this may be a custom skill named "eds" — skip silently
|
|
146
144
|
if (!installedVersion) continue
|
|
147
145
|
|
|
146
|
+
/**
|
|
147
|
+
* The skill benchmark used to live in `skill/.benchmark`, so `npx skills add` (which copies the
|
|
148
|
+
* whole skill folder from GitHub) installed it too. It now lives outside the skill folder, so
|
|
149
|
+
* remove any stale copy. This runs even when the skill is up to date, so that a removal that
|
|
150
|
+
* failed (e.g. because a file was locked) is retried on the next install instead of failing it.
|
|
151
|
+
*/
|
|
152
|
+
const benchmarkDir = join(targetDir, '.benchmark')
|
|
153
|
+
try {
|
|
154
|
+
rmSync(benchmarkDir, { recursive: true, force: true })
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.warn(
|
|
157
|
+
`Couldn't remove the stale EDS skill benchmark at ${relative(initCwd, benchmarkDir)}: ${error.message}`,
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
148
161
|
// If installed version is >= package version, skip (prevents downgrades in monorepos)
|
|
149
162
|
if (compareSemver(installedVersion, packageVersion) >= 0) {
|
|
150
163
|
console.log(`EDS skill is up to date (v${installedVersion}) at ${relative(initCwd, targetDir)}`)
|
package/skill/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eds
|
|
3
|
-
version: 1.0.
|
|
3
|
+
version: 1.0.2
|
|
4
4
|
description: The Edge Design System (EDS) is for building user interfaces for Edge & Node products. Use this skill when designing, implementing, reviewing, or polishing Edge & Node product UIs, when using `@edgeandnode/eds-react`, or when EDS is mentioned. Covers component selection, design patterns, tokens, and best practices – not just APIs. APIs are fully typed in the npm package.
|
|
5
5
|
allowed-tools:
|
|
6
6
|
- mcp__storybook__get-changed-stories
|
|
@@ -28,7 +28,7 @@ EDS is the design system for Edge & Node products. This skill teaches you how to
|
|
|
28
28
|
"mcpServers": {
|
|
29
29
|
"storybook": {
|
|
30
30
|
"type": "http",
|
|
31
|
-
"url": "https://
|
|
31
|
+
"url": "https://e4b81a8--6ab2abb8934bb76c7e8e086c.chromatic.com/mcp"
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -43,7 +43,7 @@ Add this to the project's `.mcp.json` file (create it if it doesn't exist). For
|
|
|
43
43
|
```json
|
|
44
44
|
{
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@edgeandnode/eds-react": "^1.0.
|
|
46
|
+
"@edgeandnode/eds-react": "^1.0.2",
|
|
47
47
|
"react": "^19.0.0",
|
|
48
48
|
"react-dom": "^19.0.0"
|
|
49
49
|
},
|
|
@@ -67,6 +67,8 @@ Add this to the project's `.mcp.json` file (create it if it doesn't exist). For
|
|
|
67
67
|
|
|
68
68
|
**Important:** `@edgeandnode/eds-css`, which `@edgeandnode/eds-react` depends on, disables Tailwind's default content scanning as an optimization, so you must explicitly [register your source paths with `@source` directives](https://tailwindcss.com/docs/detecting-classes-in-source-files#explicitly-registering-sources). Make sure to include all paths where Tailwind classes are used.
|
|
69
69
|
|
|
70
|
+
**Browser targets:** EDS's color tokens rely on native `light-dark()`, so the app must target Chrome 123, Safari 17.5, and Firefox 120 or newer. Otherwise, build tools transpile it (e.g. Lightning CSS, which Vite and Next.js use) and components inside `<Dark>`/`<Light>` get the page's colors (`EDSProvider` warns in the console; with Vite, only in production builds). In Next.js, add `"browserslist": ["chrome >= 123", "edge >= 123", "firefox >= 120", "safari >= 17.5", "ios_saf >= 17.5"]` to `package.json`; in Vite, set `build.target: ['chrome123', 'edge123', 'firefox120', 'safari17.5', 'ios17.5']` (it also covers CSS, and unlike `build.cssTarget`, a Vite-based Storybook picks it up).
|
|
71
|
+
|
|
70
72
|
### App Root
|
|
71
73
|
|
|
72
74
|
```tsx
|
|
@@ -80,7 +82,7 @@ function App() {
|
|
|
80
82
|
}
|
|
81
83
|
```
|
|
82
84
|
|
|
83
|
-
**Only one `EDSProvider` per app** — rendering more than one will throw an error. To
|
|
85
|
+
**Only one `EDSProvider` per app** — rendering more than one will throw an error. To render part of the UI in a different theme, wrap it in `<Dark>` or `<Light>` instead (e.g. `<Dark as="section">`).
|
|
84
86
|
|
|
85
87
|
### Theming
|
|
86
88
|
|
|
@@ -89,12 +91,12 @@ function App() {
|
|
|
89
91
|
To read or change the theme from anywhere in the app, use the `useEDS()` hook:
|
|
90
92
|
|
|
91
93
|
```tsx
|
|
92
|
-
import { useEDS } from '@edgeandnode/eds-react'
|
|
94
|
+
import { useEDS } from '@edgeandnode/eds-react/hooks'
|
|
93
95
|
|
|
94
96
|
const { theme, activeTheme, setTheme } = useEDS()
|
|
95
97
|
```
|
|
96
98
|
|
|
97
|
-
`theme` is `'dark' | 'light' | 'system'`. `activeTheme` resolves `'system'` to `'dark'` or `'light'` based on the user's OS preference. `setTheme(theme)` changes it (use `<ThemeSwitcher>` for the UI).
|
|
99
|
+
`theme` is `'dark' | 'light' | 'system'`. `activeTheme` resolves `'system'` to `'dark'` or `'light'` based on the user's OS preference. `setTheme(theme)` changes it (use `<ThemeSwitcher>` for the UI). `localTheme` is the theme of the nearest `<Dark>` or `<Light>` ancestor, or `undefined` if there's none (including inside a `Modal`, which always uses the page's theme) — use `localTheme ?? activeTheme` when rendering something that depends on the theme in JavaScript. `localThemeClass` is that ancestor's class (or `undefined` if there's none) — add it to content you render outside of that ancestor in the DOM (e.g. with `createPortal`) so it keeps its theme.
|
|
98
100
|
|
|
99
101
|
### Router Integration (Next.js)
|
|
100
102
|
|
|
@@ -165,7 +167,7 @@ import { EDSProvider } from '@edgeandnode/eds-react'
|
|
|
165
167
|
|
|
166
168
|
2. **Tailwind defaults don't exist.** Standard classes like `text-sm`, `rounded-md`, `text-gray-500` do NOT work. Use EDS tokens (`text-14`, `rounded-8`, `text-space-500`). Also `border-divider` does NOT exist; use `border-muted` or `border-subtle`.
|
|
167
169
|
|
|
168
|
-
3. **Never use primitive color tokens directly.** Always use semantic tokens (e.g. `bg-canvas` instead of `bg-space-
|
|
170
|
+
3. **Never use primitive color tokens directly.** Always use semantic tokens (e.g. `bg-canvas` instead of `bg-space-900`) to ensure UIs adapt automatically to light/dark mode. Tailwind maps custom property prefixes to utilities: `--background-color-*` → `bg-*`, `--text-color-*` → `text-*`, `--border-color-*` → `border-*`. These prefixes aren't officially documented by Tailwind, but [they work](https://github.com/tailwindlabs/tailwindcss/discussions/19020#discussioncomment-14528253) and EDS semantic tokens rely on them.
|
|
169
171
|
|
|
170
172
|
4. **Avoid opacity, use color tokens.** Don't default to `opacity-*` classes. Use semantic color tokens (e.g. `text-muted`, `text-subtle`, `bg-subtle`) which have appropriate transparency built in. Opacity is a last resort.
|
|
171
173
|
|
|
@@ -212,7 +214,7 @@ import { EDSProvider } from '@edgeandnode/eds-react'
|
|
|
212
214
|
</Button>
|
|
213
215
|
```
|
|
214
216
|
|
|
215
|
-
15. **Pass icons as components, not elements, in addon props.** Use `addonBefore={PlayIcon}` not `addonBefore={<PlayIcon alt="" />}`. The element form (`<PlayIcon alt="..." />`) is only needed when passing a non-empty `alt` or a `variant`, or when
|
|
217
|
+
15. **Pass icons as components, not elements, in addon props.** Use `addonBefore={PlayIcon}` not `addonBefore={<PlayIcon alt="" />}`. The element form (`<PlayIcon alt="..." />`) is only needed when passing a non-empty `alt` or a `variant`, or when passing it from a server component (server components can't pass functions to client components — use `addonBefore={<PlayIcon alt="" />}`). Addons have a default size tied to the parent component — don't set `size` on them.
|
|
216
218
|
|
|
217
219
|
16. **EDS icons don't shrink.** Icons from `@edgeandnode/eds-react/icons` have `shrink-0` built in. Don't add it manually — it's redundant. However, if you wrap an icon in another element (e.g. a `div`), that wrapper may still need `shrink-0` if it's a child of a `flex` container.
|
|
218
220
|
|
|
@@ -401,6 +403,9 @@ Login buttons are typically `secondary`, not `primary`. Sign-up or critical CTAs
|
|
|
401
403
|
- **Avoid `leading-*` and `tracking-*` classes.** Each font size has appropriate line height and letter spacing defaults. Overriding them breaks the typographic rhythm.
|
|
402
404
|
- **`text-caption` is for small annotations, not section headings.** Use it for labels like "STATUS", "CATEGORY", "OVERVIEW" in small text. For section headings, use regular `text-20 font-medium` or `text-18 font-medium`.
|
|
403
405
|
- **`text-10` is very small.** Use it sparingly, mostly paired with `text-caption`. For labels and small text, prefer `text-12`.
|
|
406
|
+
- **`font-sans` (Inter) is the default and inherits.** Never set it explicitly.
|
|
407
|
+
- **`font-serif` (Newsreader) is opt-in.** Use it for editorial and marketing headings. Don't use it in product UI unless the user asks for it.
|
|
408
|
+
- **`font-mono` is the system monospace font on purpose.** Don't replace it with a web font. `CodeBlock` and `CodeInline` already apply it.
|
|
404
409
|
|
|
405
410
|
### Anti-Patterns
|
|
406
411
|
|
|
@@ -520,6 +525,7 @@ Memorize this list before any UI work to avoid reimplementing existing component
|
|
|
520
525
|
| `CodeInline` | Inline code for variables, function names, etc. |
|
|
521
526
|
| `CopyButton` | Copy to clipboard. Extends `Button`. |
|
|
522
527
|
| `CurrencyInput` | Crypto amounts. Use with `useCurrencyInput` hook. |
|
|
528
|
+
| `Dark` / `Light` | Renders part of the page in the dark or light theme. |
|
|
523
529
|
| `DescriptionList` | Key-value pairs, metadata. Underused. |
|
|
524
530
|
| `Divider` | Visual separation. Horizontal or vertical. |
|
|
525
531
|
| `Icon` | Wraps icons. `src` and `alt` required. |
|
|
@@ -661,7 +667,7 @@ Some components expand to fill available width by default: `Card`, `CodeBlock`,
|
|
|
661
667
|
|
|
662
668
|
- **Address:** Handles truncation, ENS/friendly names (via `children`), copy (`'auto'` by default — shows on hover/focus). **Note:** `Address` renders its own `Avatar` using `createIdenticon(address)` — don't add a separate `Avatar` next to it or you'll get duplicate avatars.
|
|
663
669
|
- **Button & ButtonGroup:** Set `size` on the group, not nested buttons. Can mix `tertiary` and `secondary`. `orientation="vertical"` for modals/panes. `fullWidth` makes buttons equal width; `className="w-full"` makes them grow proportionally. Danger takes over primary's visual role. **Sizing:** Product UIs should default to `size="small"` for most buttons; use medium (default) only for important actions. `size="large"` is for marketing pages only.
|
|
664
|
-
- **Breadcrumbs:** Structure: `Product Name > Section > Current Page`.
|
|
670
|
+
- **Breadcrumbs:** Structure: `Product Name > Section > Current Page`. The last item defaults to `current`, so only set `current` to override that.
|
|
665
671
|
- **Chip.Group:** Requires `aria-label`.
|
|
666
672
|
- **DescriptionList:** Long values truncate with gradient fade, scroll on mobile.
|
|
667
673
|
- **Input:** For number inputs, use the `useNumberInput` hook (or `useCurrencyInput` for currency amounts) — it handles parsing, formatting, and min/max/required validation, and returns `props` to spread on `<Input>` (or `<CurrencyInput>`).
|
|
@@ -686,6 +692,7 @@ Some components carry no built-in visual styles — only behavior, semantics, or
|
|
|
686
692
|
- **`Checkbox.Area` / `Radio.Area` / `Switch.Area`** — clickable label wrappers for card-style checkable patterns; style them as `Card`s, rows, tiles, whatever the design calls for. See the "Checkable Cards" section in [patterns.md](references/patterns.md).
|
|
687
693
|
- **`Radio.Group`** — semantic wrapper around a group of `<Radio>`s. Apply your own layout (`flex`, `gap`, etc.).
|
|
688
694
|
- **`Pane`** — responsive sidebar container. Provides positioning behavior but no visual styling.
|
|
695
|
+
- **`Dark` / `Light`** — render their element (`as`, `div` by default) in the dark or light theme. They only set the color scheme and default text color, so style them as the section needs (e.g. `bg-default p-8`). `dark:`/`light:` variants on the element itself still follow the outer theme (style queries only look at ancestors), so use them on its descendants.
|
|
689
696
|
- **`ButtonOrLink`** (from `@edgeandnode/eds-react/base`) — semantic `<button>`/`<a>` wrapper with no visual styling. The other base components (`Transition`, `ExperimentalTransition`, `Presence`, `Render`, `Portal`) have transition or structural styles you shouldn't override.
|
|
690
697
|
|
|
691
698
|
### Base components
|
|
@@ -721,7 +728,7 @@ import { formatBigInt, parseBigInt, numberToBigInt, bigIntToNumber } from '@edge
|
|
|
721
728
|
```
|
|
722
729
|
|
|
723
730
|
- `cn` — concatenate class names, filtering out falsy values (like `clsx`)
|
|
724
|
-
- `useEDS` — read and change the current theme (`{ theme, activeTheme,
|
|
731
|
+
- `useEDS` — read and change the current theme (`{ theme, setTheme, activeTheme, localTheme, localThemeClass, dirProps }`); see "Theming"
|
|
725
732
|
- `useControlled` — manage controlled/uncontrolled state
|
|
726
733
|
- `useNumberInput` — numeric input validation and formatting (use with `Input`)
|
|
727
734
|
- `useCurrencyInput` — currency input validation (use with `CurrencyInput`)
|
|
@@ -31,11 +31,13 @@ Always use semantic tokens over raw color scales. They adapt to light/dark mode
|
|
|
31
31
|
| `bg-default` | Active/selected state |
|
|
32
32
|
| `bg-elevated` | Hover states |
|
|
33
33
|
| `bg-strong` | Strongly emphasized |
|
|
34
|
-
| `bg-brand-*` | Brand
|
|
34
|
+
| `bg-brand-*` | Brand blue |
|
|
35
35
|
| `bg-inverse-*` | Inverted backgrounds |
|
|
36
36
|
| `bg-code` | Inline code background |
|
|
37
37
|
| `bg-backdrop` | Modal/overlay backdrop |
|
|
38
38
|
|
|
39
|
+
The neutral backgrounds step away from `bg-canvas` in order: `canvas` → `subtle` → `muted` → `default` → `elevated` → `strong`. Each step is lighter than the previous one in dark mode and darker in light mode.
|
|
40
|
+
|
|
39
41
|
`bg-brand-*` scale: `subtlest`, `subtler`, `subtle`, `muted`, `default`, `elevated`, `strong`.
|
|
40
42
|
`bg-inverse-*` scale: `canvas`, `subtle`, `muted`, `default`, `elevated`, `strong`.
|
|
41
43
|
|
|
@@ -43,7 +45,7 @@ Always use semantic tokens over raw color scales. They adapt to light/dark mode
|
|
|
43
45
|
|
|
44
46
|
| Utility | Use For |
|
|
45
47
|
| ----------------- | ------------------------------------------ |
|
|
46
|
-
| `border-focus` | Focus rings (brand
|
|
48
|
+
| `border-focus` | Focus rings (brand blue) |
|
|
47
49
|
| `border-subtle` | Faint borders |
|
|
48
50
|
| `border-muted` | Standard borders |
|
|
49
51
|
| `border-default` | Emphasized borders |
|
|
@@ -70,22 +72,32 @@ Example: `bg-status-success-subtle`, `text-status-error-default`, `border-status
|
|
|
70
72
|
|
|
71
73
|
Use sparingly — only for custom illustrations, brand treatments, or cases where semantic tokens don't apply. **These do NOT adapt to light/dark mode.**
|
|
72
74
|
|
|
73
|
-
| Scale | Purpose | Range
|
|
74
|
-
| ----------- | ------------------------ |
|
|
75
|
-
| `space` | Dark grays | 100–
|
|
76
|
-
| `foam` | Light grays | 100–
|
|
77
|
-
| `brand` |
|
|
78
|
-
| `galactic` | Blue (info, links) | 100–
|
|
79
|
-
| `starfield` | Green (success) | 100–
|
|
80
|
-
| `solar` | Yellow/orange (warning) | 100–
|
|
81
|
-
| `sonja` | Red/pink (error, danger) | 100–
|
|
75
|
+
| Scale | Purpose | Range |
|
|
76
|
+
| ----------- | ------------------------ | ------- |
|
|
77
|
+
| `space` | Dark grays | 100–900 |
|
|
78
|
+
| `foam` | Light grays | 100–900 |
|
|
79
|
+
| `brand` | Blue (primary brand) | 100–900 |
|
|
80
|
+
| `galactic` | Blue (info, links) | 100–900 |
|
|
81
|
+
| `starfield` | Green (success) | 100–900 |
|
|
82
|
+
| `solar` | Yellow/orange (warning) | 100–900 |
|
|
83
|
+
| `sonja` | Red/pink (error, danger) | 100–900 |
|
|
84
|
+
|
|
85
|
+
Within each scale, `100` is the lightest step and `900` the darkest. For the colored scales, `500` is the base color.
|
|
82
86
|
|
|
83
87
|
```tsx
|
|
84
|
-
<div className="bg-brand-500">Brand
|
|
88
|
+
<div className="bg-brand-500">Brand blue (fixed, won't adapt to theme)</div>
|
|
85
89
|
```
|
|
86
90
|
|
|
87
91
|
## Typography
|
|
88
92
|
|
|
93
|
+
### Font Families
|
|
94
|
+
|
|
95
|
+
| Utility | Font | Use For |
|
|
96
|
+
| ------------ | ---------------- | ---------------------------------------------------------- |
|
|
97
|
+
| `font-sans` | Inter | **Default** — everything, never needs to be set (inherits) |
|
|
98
|
+
| `font-serif` | Newsreader | Opt-in: editorial and marketing headings, not product UI |
|
|
99
|
+
| `font-mono` | System monospace | Code (already applied by `CodeBlock` and `CodeInline`) |
|
|
100
|
+
|
|
89
101
|
### Font Sizes
|
|
90
102
|
|
|
91
103
|
Standard Tailwind sizes (`text-sm`, `text-lg`, `text-base`) **do not exist**. Use numeric pixel values:
|
|
@@ -154,15 +166,9 @@ Standard Tailwind spacing works (4px grid). EDS does **not** override spacing to
|
|
|
154
166
|
|
|
155
167
|
When in doubt, add more space. Dense UIs look cheap.
|
|
156
168
|
|
|
157
|
-
## Theme
|
|
158
|
-
|
|
159
|
-
| Class | Effect |
|
|
160
|
-
| ------------ | ---------------------------------------------------------- |
|
|
161
|
-
| `eds-dark` | Forces dark color scheme for this element and descendants |
|
|
162
|
-
| `eds-light` | Forces light color scheme for this element and descendants |
|
|
163
|
-
| `eds-system` | Follows the OS color scheme preference |
|
|
169
|
+
## Theme Sections
|
|
164
170
|
|
|
165
|
-
|
|
171
|
+
The `EDSProvider` `theme` prop sets the root theme. To render part of the UI in another theme, wrap it in `<Dark>` or `<Light>` (e.g. `<Dark as="section">`). They can be nested, and components inside them can read the section's theme with `useEDS().localTheme`. Menus, selects, and tooltips use the theme of the section they're in, while modals use the page's theme.
|
|
166
172
|
|
|
167
173
|
## Breakpoints
|
|
168
174
|
|
package/src/EDSContext.ts
CHANGED
|
@@ -6,6 +6,12 @@ import type { DirectionProvider } from '@base-ui/react/direction-provider'
|
|
|
6
6
|
export type Theme = 'dark' | 'light' | 'system'
|
|
7
7
|
export type ResolvedTheme = Exclude<Theme, 'system'>
|
|
8
8
|
|
|
9
|
+
export const THEME_CLASSES: Record<Theme, string> = {
|
|
10
|
+
dark: 'eds-dark',
|
|
11
|
+
light: 'eds-light',
|
|
12
|
+
system: 'eds-system',
|
|
13
|
+
}
|
|
14
|
+
|
|
9
15
|
export type ThemePersistence =
|
|
10
16
|
| 'localStorage'
|
|
11
17
|
| 'cookie'
|
|
@@ -23,3 +29,6 @@ export interface EDSContextValue {
|
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
export const EDSContext = createContext<EDSContextValue | null>(null)
|
|
32
|
+
|
|
33
|
+
/** The theme of the nearest `Dark` or `Light` ancestor, if any. */
|
|
34
|
+
export const LocalThemeContext = createContext<ResolvedTheme | undefined>(undefined)
|
package/src/EDSProvider.tsx
CHANGED
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useLayoutEffect,
|
|
7
|
+
useMemo,
|
|
8
|
+
useRef,
|
|
9
|
+
useState,
|
|
10
|
+
type ComponentProps,
|
|
11
|
+
} from 'react'
|
|
4
12
|
import { mergeProps } from '@base-ui/react'
|
|
5
13
|
import { DirectionProvider } from '@base-ui/react/direction-provider'
|
|
6
14
|
import { Tooltip } from '@base-ui/react/tooltip'
|
|
7
15
|
|
|
8
16
|
import { ButtonOrLink, type ButtonOrLinkConfigProps } from './components/base/ButtonOrLink.tsx'
|
|
9
17
|
import { Pane } from './components/Pane.tsx'
|
|
10
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
EDSContext,
|
|
20
|
+
THEME_CLASSES,
|
|
21
|
+
type ResolvedTheme,
|
|
22
|
+
type Theme,
|
|
23
|
+
type ThemePersistence,
|
|
24
|
+
} from './EDSContext.ts'
|
|
11
25
|
import { useControlled } from './hooks/useControlled.ts'
|
|
12
26
|
import { useIsHydrated } from './hooks/useIsHydrated.ts'
|
|
13
27
|
import { cn } from './utils/index.ts'
|
|
@@ -15,12 +29,6 @@ import { cn } from './utils/index.ts'
|
|
|
15
29
|
const PERSISTENCE_KEY = 'eds-active-theme'
|
|
16
30
|
const COOKIE_REGEX = new RegExp(`(?:^|; )${PERSISTENCE_KEY}=([^;]+)`)
|
|
17
31
|
|
|
18
|
-
const THEME_CLASSES: Record<Theme, string> = {
|
|
19
|
-
dark: 'eds-dark',
|
|
20
|
-
light: 'eds-light',
|
|
21
|
-
system: 'eds-system',
|
|
22
|
-
}
|
|
23
|
-
|
|
24
32
|
const VALID_THEMES: readonly Theme[] = ['dark', 'light', 'system']
|
|
25
33
|
|
|
26
34
|
function isValidTheme(value: unknown): value is Theme {
|
|
@@ -153,7 +161,7 @@ export type { EDSContextValue, ResolvedTheme, Theme, ThemePersistence } from './
|
|
|
153
161
|
* Provides global configuration and enhancements for EDS components.
|
|
154
162
|
*
|
|
155
163
|
* Note: Only one EDSProvider should be used per app, typically at the root. If you need different
|
|
156
|
-
* themes for different parts of the app, use the `
|
|
164
|
+
* themes for different parts of the app, use the `Dark` and `Light` components instead.
|
|
157
165
|
*
|
|
158
166
|
* **Next.js App Router:** add `suppressHydrationWarning` to your `<html>` tag in `app/layout.tsx`.
|
|
159
167
|
* The pre-hydration script applies the theme class to `<html>` before React hydrates (preventing a
|
|
@@ -370,6 +378,23 @@ export function EDSProvider({
|
|
|
370
378
|
}
|
|
371
379
|
}, [])
|
|
372
380
|
|
|
381
|
+
/**
|
|
382
|
+
* Warn if build tools transpiled `light-dark()` (e.g. Lightning CSS with older browser targets).
|
|
383
|
+
* Its fallback resolves tokens on `:root`, so components inside `Dark` and `Light` would get the
|
|
384
|
+
* page's colors.
|
|
385
|
+
*/
|
|
386
|
+
useEffect(() => {
|
|
387
|
+
const lightDarkTest = getComputedStyle(document.documentElement).getPropertyValue(
|
|
388
|
+
'--eds-light-dark-test',
|
|
389
|
+
)
|
|
390
|
+
if (lightDarkTest !== '' && !lightDarkTest.includes('light-dark')) {
|
|
391
|
+
// oxlint-disable-next-line no-console
|
|
392
|
+
console.warn(
|
|
393
|
+
"[EDSProvider] `light-dark()` was transpiled by your build tools, so components inside `Dark` and `Light` will use the page's colors. Target Chrome 123, Safari 17.5, and Firefox 120 or newer (see the `@edgeandnode/eds-react` README).",
|
|
394
|
+
)
|
|
395
|
+
}
|
|
396
|
+
}, [])
|
|
397
|
+
|
|
373
398
|
const edsContextValue = useMemo(
|
|
374
399
|
() => ({
|
|
375
400
|
theme,
|
|
@@ -9,7 +9,8 @@ import avatarPlaceholderRounded from '@edgeandnode/eds-react/assets/avatar-place
|
|
|
9
9
|
import { createIdenticon, PLACEHOLDER_ADDRESS } from '@edgeandnode/eds-utils'
|
|
10
10
|
|
|
11
11
|
import { useCSSPropsPolyfill, useEDS } from '../hooks/index.ts'
|
|
12
|
-
import { cn, getAssetUrl, getCSSPropsAttributes
|
|
12
|
+
import { cn, getAssetUrl, getCSSPropsAttributes } from '../utils/index.ts'
|
|
13
|
+
import { getTooltipProps } from '../utils/internal/index.ts'
|
|
13
14
|
import { AvatarMeta } from './Avatar.meta.ts'
|
|
14
15
|
import { MaybeButtonOrLink, type MaybeButtonOrLinkProps } from './base/MaybeButtonOrLink.tsx'
|
|
15
16
|
import { Tooltip, type TooltipProps } from './Tooltip.tsx'
|
|
@@ -94,7 +95,7 @@ export function Avatar({
|
|
|
94
95
|
return (
|
|
95
96
|
<Tooltip
|
|
96
97
|
content={category !== 'other' ? alt : undefined}
|
|
97
|
-
{...(
|
|
98
|
+
{...getTooltipProps(tooltip)}
|
|
98
99
|
triggerProps={renderProps}
|
|
99
100
|
>
|
|
100
101
|
<Element {...elementProps}>
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
createContext,
|
|
5
5
|
isValidElement,
|
|
6
6
|
useCallback,
|
|
7
|
+
useContext,
|
|
7
8
|
useMemo,
|
|
8
9
|
useRef,
|
|
9
10
|
useState,
|
|
10
11
|
type ComponentProps,
|
|
11
12
|
type CSSProperties,
|
|
12
|
-
type ReactElement,
|
|
13
13
|
} from 'react'
|
|
14
14
|
import { mergeProps } from '@base-ui/react'
|
|
15
15
|
import { useRenderCount, useThrottledEffect } from '@react-hookz/web'
|
|
@@ -21,12 +21,20 @@ import { ArrowLeftInteractiveIcon, DotsThreeIcon } from '@edgeandnode/eds-react/
|
|
|
21
21
|
|
|
22
22
|
import { useCSSPropsPolyfill, useCSSState, useEDS } from '../hooks/index.ts'
|
|
23
23
|
import { cn, getCSSPropsAttributes, splitProps } from '../utils/index.ts'
|
|
24
|
+
import { resolveLazy } from '../utils/internal/index.ts'
|
|
24
25
|
import { renderAddon, type AddonValue } from './base/Addon.tsx'
|
|
25
26
|
import { MaybeButtonOrLink, type MaybeButtonOrLinkProps } from './base/MaybeButtonOrLink.tsx'
|
|
26
27
|
import { BreadcrumbsItemMeta, BreadcrumbsMeta } from './Breadcrumbs.meta.ts'
|
|
27
28
|
import { Button } from './Button.tsx'
|
|
28
29
|
import { Menu } from './Menu.tsx'
|
|
29
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Whether a `Breadcrumbs.Item` is (in) the last item of `Breadcrumbs`, which makes it default to
|
|
33
|
+
* `current`. Provided through context rather than by cloning the item, so that it also works when
|
|
34
|
+
* items are wrapped in another component.
|
|
35
|
+
*/
|
|
36
|
+
const BreadcrumbsLastItemContext = createContext(false)
|
|
37
|
+
|
|
30
38
|
export interface BreadcrumbsProps
|
|
31
39
|
extends ComponentProps<'nav'>, EDSComponentProps<typeof BreadcrumbsMeta> {}
|
|
32
40
|
|
|
@@ -47,18 +55,23 @@ export function BreadcrumbsRoot({
|
|
|
47
55
|
|
|
48
56
|
const ariaLabel = passedAriaLabel !== undefined ? passedAriaLabel : 'Breadcrumbs'
|
|
49
57
|
|
|
50
|
-
// If the last `Breadcrumbs.Item` child doesn't explicitly set `current`, clone it to default
|
|
51
|
-
// `current` to `true`.
|
|
52
58
|
const processedChildren = useMemo(() => {
|
|
53
59
|
const flatChildren = flattenChildren(children)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
const lastItemIndex = flatChildren.findLastIndex(
|
|
61
|
+
(child) => isValidElement(child) && resolveLazy(child.type) === BreadcrumbsItem,
|
|
62
|
+
)
|
|
63
|
+
// If items are wrapped in another component, the last element renders the last item
|
|
64
|
+
const lastIndex =
|
|
65
|
+
lastItemIndex !== -1 ? lastItemIndex : flatChildren.findLastIndex(isValidElement)
|
|
66
|
+
return flatChildren.map((child, index) =>
|
|
67
|
+
isValidElement(child) ? (
|
|
68
|
+
<BreadcrumbsLastItemContext.Provider key={child.key} value={index === lastIndex}>
|
|
69
|
+
{child}
|
|
70
|
+
</BreadcrumbsLastItemContext.Provider>
|
|
71
|
+
) : (
|
|
72
|
+
child
|
|
73
|
+
),
|
|
74
|
+
)
|
|
62
75
|
}, [children])
|
|
63
76
|
|
|
64
77
|
const hiddenContainerRef = useRef<HTMLDivElement>(null)
|
|
@@ -249,8 +262,9 @@ export declare namespace BreadcrumbsItemProps {
|
|
|
249
262
|
addonBefore?: AddonValue | undefined
|
|
250
263
|
/**
|
|
251
264
|
* Whether this breadcrumb item represents the current page. Defaults to `true` for the last
|
|
252
|
-
* `Breadcrumbs.Item` child of `Breadcrumbs
|
|
253
|
-
*
|
|
265
|
+
* `Breadcrumbs.Item` child of `Breadcrumbs` (or the item rendered by its last child, if items
|
|
266
|
+
* are wrapped in another component), and `false` for any other item. Set explicitly to override
|
|
267
|
+
* the default.
|
|
254
268
|
*/
|
|
255
269
|
current?: boolean | undefined
|
|
256
270
|
}
|
|
@@ -267,11 +281,13 @@ export type BreadcrumbsItemProps =
|
|
|
267
281
|
|
|
268
282
|
export function BreadcrumbsItem({
|
|
269
283
|
addonBefore,
|
|
270
|
-
current
|
|
284
|
+
current: passedCurrent,
|
|
271
285
|
hideLabel,
|
|
272
286
|
children,
|
|
273
287
|
...props
|
|
274
288
|
}: BreadcrumbsItemProps) {
|
|
289
|
+
const isLastItem = useContext(BreadcrumbsLastItemContext)
|
|
290
|
+
const current = passedCurrent ?? isLastItem
|
|
275
291
|
const { rootProps, nestedProps } = splitProps(props)
|
|
276
292
|
|
|
277
293
|
const [stateRef, state] = useCSSState({
|
|
@@ -7,7 +7,8 @@ import type { EDSComponentProps } from '@edgeandnode/eds-css'
|
|
|
7
7
|
import { LoadingIcon } from '@edgeandnode/eds-react/icons'
|
|
8
8
|
|
|
9
9
|
import { useCSSPropsPolyfill, useCSSState, useEDS } from '../hooks/index.ts'
|
|
10
|
-
import { cn, getCSSPropsAttributes
|
|
10
|
+
import { cn, getCSSPropsAttributes } from '../utils/index.ts'
|
|
11
|
+
import { getTooltipProps } from '../utils/internal/index.ts'
|
|
11
12
|
import { renderAddon, type AddonValue } from './base/Addon.tsx'
|
|
12
13
|
import { ButtonOrLink, type ButtonOrLinkProps } from './base/ButtonOrLink.tsx'
|
|
13
14
|
import { ButtonMeta } from './Button.meta.ts'
|
|
@@ -132,7 +133,7 @@ export function Button({
|
|
|
132
133
|
render={(renderProps, { Element, elementProps }) => (
|
|
133
134
|
<Tooltip
|
|
134
135
|
closeOnClick={typeof props.checked === 'boolean' ? false : undefined} // If this is a toggle button, keep the tooltip open on click by default
|
|
135
|
-
{...(
|
|
136
|
+
{...getTooltipProps(tooltip)}
|
|
136
137
|
triggerProps={renderProps}
|
|
137
138
|
>
|
|
138
139
|
<Element {...elementProps}>
|