From 6add5b7bc074505e3961e4f47454f511a072af14 Mon Sep 17 00:00:00 2001 From: Robert Snow Date: Tue, 27 Jan 2026 19:15:12 -0600 Subject: [PATCH 1/2] feat: Style macro devtool (#8305) * feat: Style Macro DevTool # Conflicts: # yarn.lock * add parcel patch * small fixes * fix mergeStyles * Add README so people know how to develop this extension * add todos, fix tests, fix lint * fix dev logic * add todo * use static method to inject script * fix the patch * I don't think there is a bug here, different states get different macro hashes * remove console logs * add extension icon * use document idle instead of start to help with tab reload * fix package.json * have dev tool handle all book keeping and poll to avoid memory leak * Add architecture diagrams and explanations * Add patch back in * fix install * remove console.log * fix patch and ts error * fix lint * fix RSC * fix rsc more * Update static macros to store their data directly in a css class * fix tests * fix lint * fix handling between multiple tabs * fix polling cleanup to work with new classnames * revert button change * remove static macros extension information in production * add info to the architecture * fix merge * fix lint in test file * fix more merge issues * fix tableview styles * add location to style macro hash differentiate between hash conflicts when same style is used in multiple files * fix tests * Add more to readme * review comments * feat: Optimize style macro for build vs dev (#9479) * reduce string iterations * fix lint * fix spacing * fix logic * add tests for the style macro merging --------- Co-authored-by: Daniel Lu --- eslint.config.mjs | 10 +- packages/@react-spectrum/s2/src/TableView.tsx | 2 +- .../s2/style/__tests__/mergeStyles.test.js | 32 -- .../s2/style/__tests__/mergeStyles.test.ts | 68 ++++ .../s2/style/__tests__/style-macro.test.js | 80 ++-- packages/@react-spectrum/s2/style/runtime.ts | 26 +- .../@react-spectrum/s2/style/style-macro.ts | 91 ++++- .../dev/style-macro-chrome-plugin/.parcelrc | 9 + .../dev/style-macro-chrome-plugin/README.md | 382 ++++++++++++++++++ .../style-macro-chrome-plugin/package.json | 25 ++ .../src/background.js | 51 +++ .../src/content-script.js | 62 +++ .../style-macro-chrome-plugin/src/devtool.js | 268 ++++++++++++ .../src/devtools.html | 7 + .../src/icons/128.png | Bin 0 -> 10103 bytes .../src/icons/16.png | Bin 0 -> 877 bytes .../src/icons/32.png | Bin 0 -> 1987 bytes .../src/icons/48.png | Bin 0 -> 3413 bytes .../src/icons/96.png | Bin 0 -> 7532 bytes .../src/manifest.json | 23 ++ yarn.lock | 69 ++++ 21 files changed, 1123 insertions(+), 82 deletions(-) delete mode 100644 packages/@react-spectrum/s2/style/__tests__/mergeStyles.test.js create mode 100644 packages/@react-spectrum/s2/style/__tests__/mergeStyles.test.ts create mode 100644 packages/dev/style-macro-chrome-plugin/.parcelrc create mode 100644 packages/dev/style-macro-chrome-plugin/README.md create mode 100644 packages/dev/style-macro-chrome-plugin/package.json create mode 100644 packages/dev/style-macro-chrome-plugin/src/background.js create mode 100644 packages/dev/style-macro-chrome-plugin/src/content-script.js create mode 100644 packages/dev/style-macro-chrome-plugin/src/devtool.js create mode 100644 packages/dev/style-macro-chrome-plugin/src/devtools.html create mode 100644 packages/dev/style-macro-chrome-plugin/src/icons/128.png create mode 100644 packages/dev/style-macro-chrome-plugin/src/icons/16.png create mode 100644 packages/dev/style-macro-chrome-plugin/src/icons/32.png create mode 100644 packages/dev/style-macro-chrome-plugin/src/icons/48.png create mode 100644 packages/dev/style-macro-chrome-plugin/src/icons/96.png create mode 100644 packages/dev/style-macro-chrome-plugin/src/manifest.json diff --git a/eslint.config.mjs b/eslint.config.mjs index 809ac66aef2..ad336dabaf3 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -507,4 +507,12 @@ export default [{ rules: { "react/react-in-jsx-scope": OFF, }, -}]; +}, { + files: ["packages/dev/style-macro-chrome-plugin/**"], + languageOptions: { + globals: { + ...globals.webextensions, + ...globals.browser + } + } +}]; \ No newline at end of file diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index ed9b7d6afcb..539b564e3f3 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -1465,7 +1465,7 @@ export const Row = /*#__PURE__*/ (forwardRef as forwardRefType)(function Row row({ ...renderProps, ...tableVisualOptions - }) + (renderProps.isFocusVisible && ' ' + raw('&:before { content: ""; display: inline-block; position: sticky; inset-inline-start: 0; width: 3px; height: 100%; margin-inline-end: -3px; margin-block-end: 1px; z-index: 3; background-color: var(--rowFocusIndicatorColor)'))} + }) + (renderProps.isFocusVisible ? ' ' + raw('&:before { content: ""; display: inline-block; position: sticky; inset-inline-start: 0; width: 3px; height: 100%; margin-inline-end: -3px; margin-block-end: 1px; z-index: 3; background-color: var(--rowFocusIndicatorColor)') : '')} {...otherProps}> {selectionMode !== 'none' && selectionBehavior === 'toggle' && ( // Not sure what we want to do with this className, in Cell it currently overrides the className that would have been applied. diff --git a/packages/@react-spectrum/s2/style/__tests__/mergeStyles.test.js b/packages/@react-spectrum/s2/style/__tests__/mergeStyles.test.js deleted file mode 100644 index 00376090225..00000000000 --- a/packages/@react-spectrum/s2/style/__tests__/mergeStyles.test.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2024 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -import {mergeStyles} from '../runtime'; -import {style} from '../spectrum-theme'; - -describe('mergeStyles', () => { - it('should merge styles', () => { - let a = style({backgroundColor: 'red-1000', color: 'pink-100'}); - let b = style({fontSize: 'body-xs', backgroundColor: 'gray-50'}); - let expected = style({backgroundColor: 'gray-50', color: 'pink-100', fontSize: 'body-xs'}); - let merged = mergeStyles(a, b); - expect(merged).toBe(expected); - }); - - it('should merge with arbitrary values', () => { - let a = style({backgroundColor: 'red-1000', color: '[hotpink]'}); - let b = style({fontSize: '[15px]', backgroundColor: 'gray-50'}); - let expected = style({backgroundColor: 'gray-50', color: '[hotpink]', fontSize: '[15px]'}); - let merged = mergeStyles(a, b); - expect(merged).toBe(expected); - }); -}); diff --git a/packages/@react-spectrum/s2/style/__tests__/mergeStyles.test.ts b/packages/@react-spectrum/s2/style/__tests__/mergeStyles.test.ts new file mode 100644 index 00000000000..efb8c1f6c82 --- /dev/null +++ b/packages/@react-spectrum/s2/style/__tests__/mergeStyles.test.ts @@ -0,0 +1,68 @@ +/* + * Copyright 2024 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import {mergeStyles} from '../runtime'; +import {style} from '../spectrum-theme'; + +function stripMacro(css) { + return css.replaceAll(/ -macro-static-[0-9a-zA-Z]+/gi, '').replaceAll(/ -macro-dynamic-[0-9a-zA-Z]+/gi, ''); +} + +describe('mergeStyles', () => { + it('should merge styles', () => { + let a = style({backgroundColor: 'red-1000', color: 'pink-100'}); + let b = style({fontSize: 'body-xs', backgroundColor: 'gray-50'}); + let expected = style({backgroundColor: 'gray-50', color: 'pink-100', fontSize: 'body-xs'}); + let merged = mergeStyles(a, b); + expect(stripMacro(merged)).toBe(stripMacro(expected.toString())); + }); + + it('should merge with arbitrary values', () => { + let a = style({backgroundColor: 'red-1000', color: '[hotpink]'}); + let b = style({fontSize: '[15px]', backgroundColor: 'gray-50'}); + let expected = style({backgroundColor: 'gray-50', color: '[hotpink]', fontSize: '[15px]'}); + let merged = mergeStyles(a, b); + expect(stripMacro(merged)).toBe(stripMacro(expected.toString())); + }); + + describe('when merging styles with macros', () => { + it('should not merge multiple static macro classes', () => { + let a = style({backgroundColor: 'red-1000', color: 'pink-100'}); + let b = style({fontSize: 'body-xs', backgroundColor: 'gray-50'}); + let merged = mergeStyles(a, b); + // expect the merged styles to include two static different macro classes within the string + let macroClasses = merged.match(/-macro-static-[0-9a-zA-Z]+/g); + expect(macroClasses).toHaveLength(2); + expect(macroClasses![0] !== macroClasses![1]); + }); + + it('should not merge multiple dynamic macro classes', () => { + let a = style({backgroundColor: 'red-1000', color: {default: '[hotpink]', isDisabled: 'gray-400'}}); + let b = style({fontSize: '[15px]', backgroundColor: {default: 'gray-50', isDisabled: 'gray-400'}}); + let merged = mergeStyles(a({isDisabled: true}), b({isDisabled: false})); + let macroClasses = merged.match(/-macro-dynamic-[0-9a-zA-Z]+/g); + expect(macroClasses).toHaveLength(2); + expect(macroClasses![0] !== macroClasses![1]); + }); + + it('should retain both static and dynamic macro classes', () => { + let a = style({backgroundColor: 'red-1000', color: {default: '[hotpink]', isDisabled: 'gray-400'}}); + let b = style({fontSize: 'body-xs', backgroundColor: 'gray-50'}); + let merged = mergeStyles(a({isDisabled: true}), b); + let staticMacroClasses = merged.match(/-macro-static-[0-9a-zA-Z]+/g); + expect(staticMacroClasses).toHaveLength(1); + let dynamicMacroClasses = merged.match(/-macro-dynamic-[0-9a-zA-Z]+/g); + expect(dynamicMacroClasses).toHaveLength(1); + expect(staticMacroClasses![0] !== dynamicMacroClasses![0]); + }); + }); +}); diff --git a/packages/@react-spectrum/s2/style/__tests__/style-macro.test.js b/packages/@react-spectrum/s2/style/__tests__/style-macro.test.js index 10e1be65cb2..e4cb15540f7 100644 --- a/packages/@react-spectrum/s2/style/__tests__/style-macro.test.js +++ b/packages/@react-spectrum/s2/style/__tests__/style-macro.test.js @@ -53,9 +53,13 @@ describe('style-macro', () => { } } +.-macro-static-E8tar { + --macro-data-E8tar: {"style":{"marginTop":{":first-child":{"default":4,"lg":8}}},"loc":"undefined:undefined:undefined"}; + } + " `); - expect(js).toMatchInlineSnapshot('" Jbs1 Jbpv1"'); + expect(js).toMatchInlineSnapshot('" Jbs1 Jbpv1 -macro-static-E8tar"'); }); it('should support self references', () => { @@ -114,10 +118,14 @@ describe('style-macro', () => { } } +.-macro-static-ootVze { + --macro-data-ootVze: {"style":{"borderWidth":2,"paddingX":"edge-to-text","width":"calc(200px - self(borderStartWidth) - self(paddingStart))"},"loc":"undefined:undefined:undefined"}; + } + " `); - expect(js).toMatchInlineSnapshot('" _kc1 hc1 mCPFGYc1 lc1 SMBFGYc1 Rv1 ZjUQgKd1 -m_-mc1 -S_-Sv1"'); + expect(js).toMatchInlineSnapshot('" _kc1 hc1 mCPFGYc1 lc1 SMBFGYc1 Rv1 ZjUQgKd1 -m_-mc1 -S_-Sv1 -macro-static-ootVze"'); }); it('should support allowed overrides', () => { @@ -134,9 +142,9 @@ describe('style-macro', () => { color: 'green-400' }); - expect(js()).toMatchInlineSnapshot('" gw1 pg1"'); - expect(overrides).toMatchInlineSnapshot('" g8tmWqb1 pHJ3AUd1"'); - expect(js({}, overrides)).toMatchInlineSnapshot('" g8tmWqb1 pg1"'); + expect(js()).toMatchInlineSnapshot('" gw1 pg1 -macro-dynamic-1g1t5qe"'); + expect(overrides).toMatchInlineSnapshot('" g8tmWqb1 pHJ3AUd1 -macro-static-YWkqh"'); + expect(js({}, overrides)).toMatchInlineSnapshot('" g8tmWqb1 pg1 -macro-dynamic-w1re4y"'); }); it('should support allowed overrides for properties that expand into multiple', () => { @@ -151,9 +159,9 @@ describe('style-macro', () => { translateX: 40 }); - expect(js()).toMatchInlineSnapshot('" -_7PloMd-B1 __Ya1"'); - expect(overrides).toMatchInlineSnapshot('" -_7PloMd-D1 __Ya1"'); - expect(js({}, overrides)).toMatchInlineSnapshot('" -_7PloMd-D1 __Ya1"'); + expect(js()).toMatchInlineSnapshot('" -_7PloMd-B1 __Ya1 -macro-dynamic-1g21iuv"'); + expect(overrides).toMatchInlineSnapshot('" -_7PloMd-D1 __Ya1 -macro-static-JbY0Pb"'); + expect(js({}, overrides)).toMatchInlineSnapshot('" -_7PloMd-D1 __Ya1 -macro-dynamic-7es7uh"'); }); it('should support allowed overrides for shorthands', () => { @@ -168,9 +176,9 @@ describe('style-macro', () => { padding: 40 }); - expect(js()).toMatchInlineSnapshot('" Tk1 Qk1 Sk1 Rk1"'); - expect(overrides).toMatchInlineSnapshot('" Tm1 Qm1 Sm1 Rm1"'); - expect(js({}, overrides)).toMatchInlineSnapshot('" Tm1 Qm1 Sm1 Rm1"'); + expect(js()).toMatchInlineSnapshot('" Tk1 Qk1 Sk1 Rk1 -macro-dynamic-ov9j7t"'); + expect(overrides).toMatchInlineSnapshot('" Tm1 Qm1 Sm1 Rm1 -macro-static-JNxqEe"'); + expect(js({}, overrides)).toMatchInlineSnapshot('" Tm1 Qm1 Sm1 Rm1 -macro-dynamic-x7v9g1"'); }); it('should support allowed overrides for fontSize', () => { @@ -185,9 +193,9 @@ describe('style-macro', () => { fontSize: 'ui-xs' }); - expect(js()).toMatchInlineSnapshot('" -_6BNtrc-woabcc1 vx1"'); - expect(overrides).toMatchInlineSnapshot('" -_6BNtrc-a1 vx1"'); - expect(js({}, overrides)).toMatchInlineSnapshot('" -_6BNtrc-a1 vx1"'); + expect(js()).toMatchInlineSnapshot('" -_6BNtrc-woabcc1 vx1 -macro-dynamic-4vhxg6"'); + expect(overrides).toMatchInlineSnapshot('" -_6BNtrc-a1 vx1 -macro-static-mgSTCe"'); + expect(js({}, overrides)).toMatchInlineSnapshot('" -_6BNtrc-a1 vx1 -macro-dynamic-wufo3s"'); }); it("should support allowed overrides for values that aren't defined", () => { @@ -202,9 +210,9 @@ describe('style-macro', () => { minWidth: 32 }); - expect(js()).toMatchInlineSnapshot('" gE1"'); - expect(overrides).toMatchInlineSnapshot('" Nk1"'); - expect(js({}, overrides)).toMatchInlineSnapshot('" Nk1 gE1"'); + expect(js()).toMatchInlineSnapshot('" gE1 -macro-dynamic-6mjybw"'); + expect(overrides).toMatchInlineSnapshot('" Nk1 -macro-static-TMcWFd"'); + expect(js({}, overrides)).toMatchInlineSnapshot('" Nk1 gE1 -macro-dynamic-1255f06"'); }); it('should support runtime conditions', () => { @@ -258,9 +266,9 @@ describe('style-macro', () => { " `); - expect(js({})).toMatchInlineSnapshot('" gH1 pt1"'); - expect(js({isHovered: true})).toMatchInlineSnapshot('" gF1 po1"'); - expect(js({isPressed: true})).toMatchInlineSnapshot('" gE1 pm1"'); + expect(js({})).toMatchInlineSnapshot('" gH1 pt1 -macro-dynamic-1e9ks2s"'); + expect(js({isHovered: true})).toMatchInlineSnapshot('" gF1 po1 -macro-dynamic-fs3pp9"'); + expect(js({isPressed: true})).toMatchInlineSnapshot('" gE1 pm1 -macro-dynamic-qy1zq2"'); }); it('should support nested runtime conditions', () => { @@ -301,10 +309,10 @@ describe('style-macro', () => { " `); - expect(js({})).toMatchInlineSnapshot('" gH1"'); - expect(js({isHovered: true})).toMatchInlineSnapshot('" gF1"'); - expect(js({isSelected: true})).toMatchInlineSnapshot('" g_h1"'); - expect(js({isSelected: true, isHovered: true})).toMatchInlineSnapshot('" g31"'); + expect(js({})).toMatchInlineSnapshot('" gH1 -macro-dynamic-z0gpn3"'); + expect(js({isHovered: true})).toMatchInlineSnapshot('" gF1 -macro-dynamic-1rfxkr1"'); + expect(js({isSelected: true})).toMatchInlineSnapshot('" g_h1 -macro-dynamic-tk9x4e"'); + expect(js({isSelected: true, isHovered: true})).toMatchInlineSnapshot('" g31 -macro-dynamic-1defke2"'); }); it('should support variant runtime conditions', () => { @@ -318,9 +326,9 @@ describe('style-macro', () => { } }); - expect(js({variant: 'accent'})).toMatchInlineSnapshot('" gY1"'); - expect(js({variant: 'primary'})).toMatchInlineSnapshot('" gjQquMe1"'); - expect(js({variant: 'secondary'})).toMatchInlineSnapshot('" gw1"'); + expect(js({variant: 'accent'})).toMatchInlineSnapshot('" gY1 -macro-dynamic-6gbj4w"'); + expect(js({variant: 'primary'})).toMatchInlineSnapshot('" gjQquMe1 -macro-dynamic-aqv4wq"'); + expect(js({variant: 'secondary'})).toMatchInlineSnapshot('" gw1 -macro-dynamic-66ywce"'); }); it('supports runtime conditions nested inside css conditions', () => { @@ -354,8 +362,8 @@ describe('style-macro', () => { " `); - expect(js({})).toMatchInlineSnapshot('" plb1"'); - expect(js({isSelected: true})).toMatchInlineSnapshot('" ple1"'); + expect(js({})).toMatchInlineSnapshot('" plb1 -macro-dynamic-qa0mhq"'); + expect(js({isSelected: true})).toMatchInlineSnapshot('" ple1 -macro-dynamic-1inxdsx"'); }); it('should expand shorthand properties to longhands', () => { @@ -363,7 +371,7 @@ describe('style-macro', () => { padding: 24 }); - expect(js).toMatchInlineSnapshot('" Th1 Qh1 Sh1 Rh1"'); + expect(js).toMatchInlineSnapshot('" Th1 Qh1 Sh1 Rh1 -macro-static-tfFFV"'); expect(css).toMatchInlineSnapshot(` "@layer _.a; @@ -388,6 +396,10 @@ describe('style-macro', () => { } } +.-macro-static-tfFFV { + --macro-data-tfFFV: {"style":{"padding":24},"loc":"undefined:undefined:undefined"}; + } + " `); }); @@ -406,6 +418,10 @@ describe('style-macro', () => { } } +.-macro-static-S2MtWd { + --macro-data-S2MtWd: {"style":{"backgroundColor":"blue-1000/50"},"loc":"undefined:undefined:undefined"}; + } + " `); }); @@ -427,6 +443,10 @@ describe('style-macro', () => { } } +.-macro-static-sFmj5 { + --macro-data-sFmj5: {"style":{"--foo":{"type":"backgroundColor","value":"gray-300"}},"loc":"undefined:undefined:undefined"}; + } + " `); }); diff --git a/packages/@react-spectrum/s2/style/runtime.ts b/packages/@react-spectrum/s2/style/runtime.ts index 5b567e2ab56..370fcb7b675 100644 --- a/packages/@react-spectrum/s2/style/runtime.ts +++ b/packages/@react-spectrum/s2/style/runtime.ts @@ -39,20 +39,31 @@ import {StyleString} from './types'; export function mergeStyles(...styles: (StyleString | null | undefined)[]): StyleString { let definedStyles = styles.filter(Boolean) as StyleString[]; if (definedStyles.length === 1) { - return definedStyles[0]; + let first = definedStyles[0]; + if (typeof first !== 'string') { + // static macro has a toString method so that we generate the style macro map for the entry + // it's automatically called in other places, but for our merging, we have to call it ourselves + return (first as StyleString).toString() as StyleString; + } + return first; } - let map = new Map(); + let map = new Map(); + for (let style of definedStyles) { - for (let [k, v] of parse(style)) { + // must call toString here for the static macro + let str = style.toString(); + + for (let [k, v] of parse(str)) { map.set(k, v); } } - + let res = ''; for (let value of map.values()) { res += value; } + return res as StyleString; } @@ -74,7 +85,12 @@ function parse(s: string) { } let property = s.slice(start, condition); - properties.set(property, (properties.get(property) || '') + ' ' + s.slice(start, i)); + if (process.env.NODE_ENV !== 'production' && property.startsWith('-macro-')) { + let value = s.slice(start, i); + properties.set(value, ' ' + value); + } else { + properties.set(property, (properties.get(property) || '') + ' ' + s.slice(start, i)); + } } function readValue() { diff --git a/packages/@react-spectrum/s2/style/style-macro.ts b/packages/@react-spectrum/s2/style/style-macro.ts index 8d1fd77b2bb..8286f4dfa8a 100644 --- a/packages/@react-spectrum/s2/style/style-macro.ts +++ b/packages/@react-spectrum/s2/style/style-macro.ts @@ -176,7 +176,7 @@ export function parseArbitraryValue(value: Value): string | undefined { return value.slice(1, -1); } else if ( typeof value === 'string' && ( - /^(var|calc|min|max|clamp|round|mod|rem|sin|cos|tan|asin|acos|atan|atan2|pow|sqrt|hypot|log|exp|abs|sign)\(.+\)$/.test(value) || + /^(var|calc|min|max|clamp|round|mod|rem|sin|cos|tan|asin|acos|atan|atan2|pow|sqrt|hypot|log|exp|abs|sign)\(.+\)$/.test(value) || /^(inherit|initial|unset)$/.test(value) ) ) { @@ -205,6 +205,8 @@ interface MacroContext { addAsset(asset: {type: string, content: string}): void } +let isCompilingDependencies: boolean | null | string = false; + export function createTheme(theme: T): StyleFunction, 'default' | Extract> { let properties = new Map>(Object.entries(theme.properties).map(([k, v]) => { if (!Array.isArray(v) && v.cssProperties) { @@ -280,8 +282,11 @@ export function createTheme(theme: T): StyleFunction(theme: T): StyleFunction(); - let js = 'let rules = " ";\n'; + let js = process.env.NODE_ENV !== 'production' + ? 'let rules = " ", currentRules = {};\n' + : 'let rules = " ";\n'; if (allowedOverrides?.length) { for (let property of allowedOverrides) { let shorthand = theme.shorthands[property]; @@ -315,7 +322,7 @@ export function createTheme(theme: T): StyleFunction(theme: T): StyleFunction classNamePrefix(p, p)).join('|')})[^\\s]+/g`; + let macroPart = process.env.NODE_ENV !== 'production' ? '|-macro\\$' : ''; + let regex = `/(?:^|\\s)(${[...allowedOverridesSet].map(p => classNamePrefix(p, p)).join('|')}${macroPart})[^\\s]+/g`; if (loop) { - js += `let matches = (overrides || '').matchAll(${regex});\n`; + js += `let matches = String(overrides || '').matchAll(${regex});\n`; js += 'for (let p of matches) {\n'; js += loop; js += ' rules += p[0];\n'; js += '}\n'; } else { - js += `rules += ((overrides || '').match(${regex}) || []).join('')\n`; + js += `rules += (String(overrides || '').match(${regex}) || []).join('')\n`; } } @@ -375,6 +383,15 @@ export function createTheme(theme: T): StyleFunction(theme: T): StyleFunction(theme: T): StyleFunction(theme: T): StyleFunction(theme: T): StyleFunction rule.copy()), this.prelude, this.layer); + return new AtRule(this.rules.map(rule => rule.copy()), this.prelude, this.layer, this.themeCondition); } toCSS(rulesByLayer: Map, preludes: string[] = [], layer?: string): void { @@ -774,6 +829,13 @@ class AtRule extends GroupRule { super.toCSS(rulesByLayer, preludes, layer); preludes?.pop(); } + + toJS(allowedOverridesSet: Set, indent?: string): string { + conditionStack.push(this.themeCondition || this.prelude); + let res = super.toJS(allowedOverridesSet, indent); + conditionStack.pop(); + return res; + } } /** A rule that applies conditionally at runtime. */ @@ -794,7 +856,10 @@ class ConditionalRule extends GroupRule { } toJS(allowedOverridesSet: Set, indent = ''): string { - return `${indent}if (props.${this.condition}) {\n${super.toJS(allowedOverridesSet, indent + ' ')}\n${indent}}`; + conditionStack.push(this.condition); + let res = `${indent}if (props.${this.condition}) {\n${super.toJS(allowedOverridesSet, indent + ' ')}\n${indent}}`; + conditionStack.pop(); + return res; } } diff --git a/packages/dev/style-macro-chrome-plugin/.parcelrc b/packages/dev/style-macro-chrome-plugin/.parcelrc new file mode 100644 index 00000000000..f497a196e5f --- /dev/null +++ b/packages/dev/style-macro-chrome-plugin/.parcelrc @@ -0,0 +1,9 @@ +{ + "extends": "@parcel/config-webextension", + "transformers": { + "*.{js,mjs,jsx,cjs,ts,tsx}": [ + "@parcel/transformer-js", + "@parcel/transformer-react-refresh-wrap" + ] + } +} diff --git a/packages/dev/style-macro-chrome-plugin/README.md b/packages/dev/style-macro-chrome-plugin/README.md new file mode 100644 index 00000000000..bdd967ff3ad --- /dev/null +++ b/packages/dev/style-macro-chrome-plugin/README.md @@ -0,0 +1,382 @@ +# style-macro-chrome-plugin + +This is a chrome plugin to assist in debugging the styles applied by the React Spectrum Style Macro. + +## Expected Usage + +Until the plugin is published to the Chrome web extension store, the easiest thing to do is to build using the command +``` +yarn workspace style-macro-chrome-plugin build +``` + +This will create a dist directory in the directory `packages/dev/style-macro-chrome-plugin`, you should copy this directory to somewhere permanent on your machine. + +Next, open Chrome and go to [chrome://extensions/](chrome://extensions/). + +Load an unpacked extension, it's a button in the top left, and navigate to the dist directory. + +The extension is now registered in Chrome and you can go to storybook or docs, wherever you are working. + +Inspect an element on the page to open dev tools and go to the Style Macro panel. + +## Local development + +From the root of our monopackage, run + +``` +yarn +yarn workspace style-macro-chrome-plugin start +// or build to avoid refresh bugs in HMR +yarn workspace style-macro-chrome-plugin build +``` + +This will create a dist directory in the directory `packages/dev/style-macro-chrome-plugin` which will update anytime the code changes and results in a rebuild. + +Now follow the instructions in the above section starting from "Next, open chrome". + +## Troubleshooting + +If the panel isn't updating with styles, try closing the dev tools and reopening it. + +If the extension doesn't appear to have the latest code, try closing the dev tools and reopening it. You may also want to go to the extensions page and either "refresh" or remove and re-add the extension. + +If every tab you have open (or many of them) reload when you make local changes to the extension, then go into the extension settings and limit it to `localhost` or something appropriate. + +## ToDos + +- [ ] Would be pretty cool if we could match a style condition to trigger it, like hover +- [ ] Our own UI ?? +- [ ] Filtering +- [ ] Resolve css variables inline +- [ ] Link to file on the side instead of grouping by filename? +- [ ] Add classname that is applying style? + +## Extension Architecture + +This extension uses Chrome's standard extension architecture with three main components that communicate via message passing. + +### Components + +#### 1. **Page Context** (style-macro runtime + MutationObserver) +- **Location**: Runs in the actual page's JavaScript context +- **Responsibility**: + - Generates macro metadata (hash, location, styles) when style macro is evaluated + - Hosts MutationObserver that watches selected element for className changes +- **Storage**: None - static macros embed data in CSS, dynamic macros send messages +- **Communication**: + - For static macros: Embeds data in CSS custom property `--macro-data-{hash}` (unique per macro) + - For dynamic macros: Sends `window.postMessage({ action: 'stylemacro-update-macros', hash, loc, style })` to content script + - For className changes: Sends `window.postMessage({ action: 'stylemacro-class-changed', elementId })` to content script + +#### 2. **Content Script** (`content-script.js`) +- **Location**: Isolated sandboxed environment injected into the page +- **Scope**: Acts as a message forwarder between page and extension +- **Responsibility**: + - Listens for `window.postMessage({ action: 'stylemacro-update-macros' })` from the page and forwards to background script + - Forwards `window.postMessage({ action: 'stylemacro-class-changed' })` from page to background script +- **Storage**: None - all macro data is stored in DevTools +- **Communication**: + - Receives: + - `window.postMessage({ action: 'stylemacro-update-macros', hash, loc, style })` from page + - `window.postMessage({ action: 'stylemacro-class-changed', elementId })` from page + - Sends: + - `chrome.runtime.sendMessage({ action: 'stylemacro-update-macros', hash, loc, style })` to background + - `chrome.runtime.sendMessage({ action: 'stylemacro-class-changed', elementId })` to background + +#### 3. **Background Script** (`background.js`) +- **Location**: Service worker (isolated context) +- **Responsibility**: Acts as a message broker between DevTools and content scripts +- **State**: Maintains a map of DevTools connections per tab +- **Communication**: + - Receives: + - `chrome.runtime.onConnect({ name: 'devtools-page' })` from DevTools + - `port.onMessage({ type: 'stylemacro-init' })` from DevTools + - `chrome.runtime.onMessage({ action: 'stylemacro-update-macros', hash, loc, style })` from content script + - `chrome.runtime.onMessage({ action: 'stylemacro-class-changed', elementId })` from content script + - Sends: + - `port.postMessage({ action: 'stylemacro-update-macros', hash, loc, style })` to DevTools + - `port.postMessage({ action: 'stylemacro-class-changed', elementId })` to DevTools + +#### 4. **DevTools Panel** (`devtool.js`) +- **Location**: DevTools sidebar panel context +- **Responsibility**: + - Stores all dynamic macro data in a local Map: `macroData[hash] = { loc, style }` + - Extracts macro class names from selected element: + - Static macros: `-macro-static-{hash}` → reads `--macro-data-{hash}` custom property via `getComputedStyle()` + - Dynamic macros: `-macro-dynamic-{hash}` → looks up data from local storage + - Displays style information in sidebar + - **Automatic Updates**: Sets up a MutationObserver on the selected element to detect className changes and automatically refreshes the panel + - **Cleanup**: Every 5 minutes, checks the DOM for each stored hash and removes data for macros that no longer exist +- **Storage**: `Map` - stores all dynamic macro data +- **Mutation Observer**: + - Created when an element is selected via `chrome.devtools.panels.elements.onSelectionChanged` + - Watches the selected element's `class` attribute for changes + - Disconnects when: + - A new element is selected + - The DevTools connection is closed + - Triggers automatic panel refresh when className changes +- **Communication**: + - Receives: + - `port.onMessage({ action: 'stylemacro-update-macros', hash, loc, style })` from background (stores data and refreshes) + - `port.onMessage({ action: 'stylemacro-class-changed', elementId })` from background (triggers refresh) + - Sends: + - `chrome.runtime.connect({ name: 'devtools-page' })` to establish connection + - `port.postMessage({ type: 'stylemacro-init', tabId })` to background + +### Message Flow Diagrams + +#### Flow 1a: Static Macro Lookup (DevTools reads CSS) + +Static macros are generated when style macro conditions don't change at runtime. The macro data is embedded directly into the CSS as a uniquely-named custom property. + +``` +┌─────────────────┐ +│ DevTools Panel │ User selects element with -macro-static-{hash} class +└────────┬────────┘ + │ Extract hash from className + │ Read --macro-data-{hash} via getComputedStyle($0) + ↓ +┌─────────────────┐ +│ Page DOM/CSS │ Returns custom property value for specific hash +└────────┬────────┘ + │ getPropertyValue('--macro-data-{hash}') + │ { loc: "...", style: {...} } + ↓ +┌─────────────────┐ +│ DevTools Panel │ Parses and displays in sidebar +└─────────────────┘ +``` + +**Key Design**: Each static macro has its own uniquely-named custom property (`--macro-data-{hash}`), which avoids CSS cascade issues when reading multiple macro data from the same element. + +#### Flow 1b: Dynamic Macro Updates (Page → DevTools) + +Dynamic macros are generated when style macro conditions can change at runtime. Updates are sent via message passing and stored directly in DevTools. + +``` +┌─────────────────┐ +│ Page Context │ +│ (style-macro) │ +└────────┬────────┘ + │ window.postMessage({ action: 'stylemacro-update-macros', hash, loc, style }) + ↓ +┌─────────────────┐ +│ Content Script │ Forwards message (no storage) +└────────┬────────┘ + │ chrome.runtime.sendMessage({ action: 'stylemacro-update-macros', hash, loc, style }) + ↓ +┌─────────────────┐ +│ Background │ Looks up DevTools connection for tabId +└────────┬────────┘ + │ port.postMessage({ action: 'stylemacro-update-macros', hash, loc, style }) + ↓ +┌─────────────────┐ +│ DevTools Panel │ Stores in macroData Map and triggers sidebar refresh +└─────────────────┘ +``` + +#### Flow 2: Display Macro Data (Synchronous Lookup) + +When the user selects an element or the panel refreshes, DevTools looks up macro data synchronously from its local storage. + +``` +┌─────────────────┐ +│ DevTools Panel │ User selects element with -macro-dynamic-{hash} class +└────────┬────────┘ + │ Extract hash from className + ↓ +┌─────────────────┐ +│ DevTools Panel │ Look up macroData.get(hash) +│ Local Storage │ Returns { loc, style } if available +└────────┬────────┘ + │ { loc: "...", style: {...} } or null + ↓ +┌─────────────────┐ +│ DevTools Panel │ Display in sidebar (or show nothing if null) +└─────────────────┘ +``` + +**Note**: If macro data hasn't been received yet for a hash, it will appear empty until the next `stylemacro-update-macros` message arrives and triggers a refresh. + +#### Flow 3: Macro Data Cleanup (Automated) + +Every 5 minutes, DevTools checks if stored macro hashes are still in use on the page and removes stale data. + +``` +┌─────────────────┐ +│ DevTools Panel │ Every 5 minutes +└────────┬────────┘ + │ For each hash in macroData Map: + │ chrome.devtools.inspectedWindow.eval( + │ `!!document.querySelector('.-macro-dynamic-${hash}')` + │ ) + ↓ +┌─────────────────┐ +│ Page DOM │ Checks if elements with macro classes exist +└────────┬────────┘ + │ Returns true/false for each hash + ↓ +┌─────────────────┐ +│ DevTools Panel │ Removes stale entries from macroData Map +│ │ macroData.delete(hash) for non-existent elements +└─────────────────┘ +``` + +#### Flow 4: Automatic Updates on className Changes (MutationObserver) + +When you select an element, the DevTools panel automatically watches for className changes and refreshes the panel. + +``` +┌─────────────────┐ +│ DevTools Panel │ User selects element in Elements panel +└────────┬────────┘ + │ chrome.devtools.panels.elements.onSelectionChanged + │ + │ chrome.devtools.inspectedWindow.eval(` + │ // Disconnect old observer (if any) + │ if (window.__styleMacroObserver) { + │ window.__styleMacroObserver.disconnect(); + │ } + │ + │ // Create new MutationObserver on $0 + │ window.__styleMacroObserver = new MutationObserver(() => { + │ window.postMessage({ + │ action: 'stylemacro-class-changed', + │ elementId: $0.__devtoolsId + │ }, '*'); + │ }); + │ + │ window.__styleMacroObserver.observe($0, { + │ attributes: true, + │ attributeFilter: ['class'] + │ }); + │ `) + ↓ +┌─────────────────┐ +│ Page DOM │ MutationObserver active on selected element +└────────┬────────┘ + │ + │ ... User interacts with page, element's className changes ... + │ + │ MutationObserver detects class attribute change + │ window.postMessage({ action: 'stylemacro-class-changed', elementId }, '*') + ↓ +┌─────────────────┐ +│ Content Script │ Receives window message, forwards to extension +└────────┬────────┘ + │ chrome.runtime.sendMessage({ action: 'stylemacro-class-changed', elementId }) + ↓ +┌─────────────────┐ +│ Background │ Looks up DevTools connection for tabId +└────────┬────────┘ + │ port.postMessage({ action: 'stylemacro-class-changed', elementId }) + ↓ +┌─────────────────┐ +│ DevTools Panel │ Verifies elementId matches currently selected element +│ │ Triggers full panel refresh (re-reads classes, re-queries macros) +└─────────────────┘ + +When selection changes or panel closes: + ↓ +┌─────────────────┐ +│ DevTools Panel │ Calls disconnectObserver() +└────────┬────────┘ + │ chrome.devtools.inspectedWindow.eval(` + │ if (window.__styleMacroObserver) { + │ window.__styleMacroObserver.disconnect(); + │ window.__styleMacroObserver = null; + │ } + │ `) + ↓ +┌─────────────────┐ +│ Page DOM │ Old observer disconnected, new observer created for new selection +└─────────────────┘ +``` + +**Key Benefits:** +- Panel automatically refreshes when element classes change (e.g., hover states, conditional styles) +- No manual refresh needed +- Observer is cleaned up properly to prevent memory leaks +- Each element has its own unique tracking ID to prevent cross-contamination + +### Key Technical Details + +#### Why Background Script is Needed +Chrome extensions prevent direct communication between DevTools and content scripts for security reasons. The background script acts as a trusted intermediary. + +#### Static vs Dynamic Macros + +The style macro generates different class name patterns based on whether the styles can change at runtime: + +**Static Macros** (`-macro-static-{hash}`): +- Used when all style conditions are static (e.g., `style({ color: 'red' })`) +- Macro data is embedded in CSS as a uniquely-named custom property: `--macro-data-{hash}: '{...JSON...}'` +- DevTools reads the specific custom property via `getComputedStyle($0).getPropertyValue('--macro-data-{hash}')` +- Unique naming avoids CSS cascade issues when multiple macros are applied to the same element + +**Dynamic Macros** (`-macro-dynamic-{hash}`): +- Used when style conditions can change (e.g., `style({color: {default: 'blue', isActive: 'red'}})`) +- Macro data is sent via `window.postMessage({ action: 'stylemacro-update-macros', ... })` whenever conditions change +- Content script forwards data to DevTools, which stores it in a local Map +- Enables real-time updates when props/state change + +#### Data Storage +- **Static Macros**: Data embedded in CSS as uniquely-named custom properties `--macro-data-{hash}`, read via `getComputedStyle($0).getPropertyValue('--macro-data-{hash}')` + - Each macro has its own custom property name to prevent cascade conflicts + - Example: `.-macro-static-abc123 { --macro-data-abc123: '{"style": {...}, "loc": "..."}'; }` +- **Dynamic Macros**: Data stored in DevTools panel's `macroData` Map +- **No Content Script Storage**: Content script only forwards messages, doesn't store macro data +- **Lifetime**: Macro data persists in DevTools for the duration of the DevTools session +- **Cleanup**: Stale macro data (for elements no longer in DOM) is removed every 5 minutes + +#### Connection Management +- **DevTools → Background**: Uses persistent `chrome.runtime.connect()` with port-based messaging +- **Content Script → Background**: Uses one-time `chrome.runtime.sendMessage()` calls +- **Background tracks**: Map of `tabId → DevTools port` for routing messages + +#### Data Structure + +**Static Macros (in CSS):** +```css +.-macro-static-zsZ9Dc { + --macro-data-zsZ9Dc: '{"style":{"paddingX":"4"},"loc":"packages/@react-spectrum/s2/src/Button.tsx:67"}'; +} +``` + +**Dynamic Macros (in DevTools panel's macroData Map):** +```javascript +Map { + "zsZ9Dc" => { + loc: "packages/@react-spectrum/s2/src/Button.tsx:67", + style: { + "paddingX": "4", + // ... more CSS properties + } + } +} +``` + +**Note**: +- Static macro data is stored in CSS with uniquely-named custom properties +- Dynamic macro data is stored directly in the DevTools panel context +- The content script acts purely as a message forwarder and doesn't store any data + +#### Message Types + +| Message Type | Direction | Purpose | +|-------------|-----------|---------| +| `stylemacro-update-macros` | Page → Content → Background → DevTools | Send macro data (hash, loc, style) to be stored in DevTools | +| `stylemacro-init` | DevTools → Background | Establish connection with tabId | +| `stylemacro-class-changed` | Page → Content → Background → DevTools | Notify that selected element's className changed | + +### Debugging + +Enable debug logs by uncommenting the `console.log()` lines in each component: +- **DevTools Panel**: `devtool.js` → `debugLog()` function +- **Content Script**: `content-script.js` → `debugLog()` function +- **Background Script**: Already logging to service worker console + +View logs in: +- **Page Console**: Content Script and DevTools Panel logs (with `[Content Script]` and `[DevTools]` prefixes) +- **Service Worker Console**: Background Script logs (go to `chrome://extensions` → click "service worker") + diff --git a/packages/dev/style-macro-chrome-plugin/package.json b/packages/dev/style-macro-chrome-plugin/package.json new file mode 100644 index 00000000000..93248a0d6db --- /dev/null +++ b/packages/dev/style-macro-chrome-plugin/package.json @@ -0,0 +1,25 @@ +{ + "name": "style-macro-chrome-plugin", + "version": "0.1.0", + "scripts": { + "start": "parcel watch src/manifest.json --host localhost --config .parcelrc", + "build": "parcel build src/manifest.json --config .parcelrc" + }, + "devDependencies": { + "@parcel/config-default": "^2.16.3", + "@parcel/config-webextension": "^2.16.3", + "@parcel/core": "^2.16.3", + "@parcel/transformer-js": "^2.16.3", + "parcel": "^2.16.3" + }, + "rsp": { + "type": "cli" + }, + "repository": { + "type": "git", + "url": "https://github.com/adobe/react-spectrum" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/dev/style-macro-chrome-plugin/src/background.js b/packages/dev/style-macro-chrome-plugin/src/background.js new file mode 100644 index 00000000000..6524078c5a0 --- /dev/null +++ b/packages/dev/style-macro-chrome-plugin/src/background.js @@ -0,0 +1,51 @@ +// Keep track of DevTools connections per tab +const devtoolsConnections = new Map(); + +// Listen for connections from DevTools +chrome.runtime.onConnect.addListener((port) => { + if (port.name === 'devtools-page') { + let tabId; + + // Listen for messages from DevTools + const messageListener = (message) => { + if (message.type === 'stylemacro-init') { + tabId = message.tabId; + devtoolsConnections.set(tabId, port); + console.log(`[Background] DevTools connected for tab ${tabId}`); + } + }; + + port.onMessage.addListener(messageListener); + + // Clean up when DevTools disconnects + port.onDisconnect.addListener(() => { + if (tabId) { + devtoolsConnections.delete(tabId); + console.log(`DevTools disconnected for tab ${tabId}`); + } + }); + } +}); + +// Listen for messages from content scripts +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + const tabId = sender.tab?.id; + + if (!tabId) { + return; + } + + // Forward messages from content script to DevTools + if (message.action === 'stylemacro-update-macros' || message.action === 'stylemacro-class-changed') { + console.log(`[Background] Forwarding ${message.action} from content script to DevTools, tabId: ${tabId}`); + const devtoolsPort = devtoolsConnections.get(tabId); + if (devtoolsPort) { + devtoolsPort.postMessage(message); + } else { + console.warn(`[Background] No DevTools connection found for tab ${tabId}`); + } + } + + return false; // Don't keep channel open +}); + diff --git a/packages/dev/style-macro-chrome-plugin/src/content-script.js b/packages/dev/style-macro-chrome-plugin/src/content-script.js new file mode 100644 index 00000000000..be2418379bf --- /dev/null +++ b/packages/dev/style-macro-chrome-plugin/src/content-script.js @@ -0,0 +1,62 @@ + +if (window.__macrosLoaded) { + return; +} +window.__macrosLoaded = true; + +let debugLog = (...args) => { + // console.log('[Content Script]', ...args); +}; + +window.addEventListener('message', function (event) { + // Only accept messages from the same frame + if (event.source !== window) { + return; + } + + var message = event.data; + + // Only accept messages that we know are ours. Note that this is not foolproof + // and the page can easily spoof messages if it wants to. + if (message && typeof message === 'object') { + if (message.action === 'stylemacro-update-macros') { + debugLog('Forwarding stylemacro-update-macros for hash:', message.hash); + + // if this script is run multiple times on the page, then only handle it once + event.stopImmediatePropagation(); + event.stopPropagation(); + + // Forward message directly to background script (which forwards to DevTools) + try { + chrome.runtime.sendMessage({ + action: 'stylemacro-update-macros', + hash: message.hash, + loc: message.loc, + style: message.style + }); + } catch (err) { + debugLog('Failed to send stylemacro-update-macros message:', err); + } + } else if (message.action === 'stylemacro-class-changed') { + // Forward class-changed messages from page context to background script + debugLog('Forwarding stylemacro-class-changed for element:', message.elementId); + + // if this script is run multiple times on the page, then only handle it once + event.stopImmediatePropagation(); + event.stopPropagation(); + + try { + chrome.runtime.sendMessage({ + action: 'stylemacro-class-changed', + elementId: message.elementId + }); + } catch (err) { + debugLog('Failed to send stylemacro-class-changed message:', err); + } + } + } +}); + +// No longer need to listen for get-macro requests or manage cleanup +// since macro data is stored directly in DevTools + diff --git a/packages/dev/style-macro-chrome-plugin/src/devtool.js b/packages/dev/style-macro-chrome-plugin/src/devtool.js new file mode 100644 index 00000000000..7587534a07f --- /dev/null +++ b/packages/dev/style-macro-chrome-plugin/src/devtool.js @@ -0,0 +1,268 @@ + +chrome.devtools.panels.elements.createSidebarPane('Style Macros', (sidebar) => { + sidebar.setObject({}); + + // Helper function to log to both DevTools-for-DevTools console and inspected page console + const debugLog = (...args) => { + // console.log(...args); // Logs to DevTools-for-DevTools console + // const message = args.map(arg => + // typeof arg === 'object' ? JSON.stringify(arg) : String(arg) + // ).join(' '); + // chrome.devtools.inspectedWindow.eval(`console.log('[DevTools]', ${JSON.stringify(message)})`); + }; + + const backgroundPageConnection = chrome.runtime.connect({name: 'devtools-page'}); + + // Monitor connection status + backgroundPageConnection.onDisconnect.addListener(() => { + debugLog('ERROR: Background connection disconnected!', chrome.runtime.lastError); + // Clean up observer when connection is lost + disconnectObserver(); + }); + + // Initialize connection with the background script + debugLog('Initializing connection with tabId:', chrome.devtools.inspectedWindow.tabId); + backgroundPageConnection.postMessage({ + type: 'stylemacro-init', + tabId: chrome.devtools.inspectedWindow.tabId + }); + debugLog('Init message sent to background'); + + // Store macro data directly in DevTools + const macroData = new Map(); + + // Track mutation observer for selected element + let currentObserver = null; + let currentElementId = null; + + // Listen for messages from content script (via background script) + backgroundPageConnection.onMessage.addListener((message) => { + debugLog('Message from background:', message); + + if (message.action === 'stylemacro-update-macros') { + debugLog('Received stylemacro-update-macros for hash:', message.hash); + // Store the macro data directly in DevTools + macroData.set(message.hash, { + loc: message.loc, + style: message.style + }); + debugLog('Stored macro data, total macros:', macroData.size); + // Refresh the panel to show updated data + update(); + } else if (message.action === 'stylemacro-class-changed') { + debugLog('Received stylemacro-class-changed notification for element:', message.elementId); + // Only update if the changed element is the one we're currently watching + if (message.elementId === currentElementId) { + debugLog('Class changed on watched element, updating panel...'); + update(); + } + } + }); + + // Get macro data from local storage + const getDynamicMacroData = (hash) => { + debugLog('Looking up dynamic macro with hash:', hash); + const data = macroData.get(hash); + debugLog('Found data:', !!data); + return data || null; + }; + + function getMacroData(className) { + let promise = new Promise((resolve) => { + debugLog('Getting macro data for:', className); + chrome.devtools.inspectedWindow.eval(`window.getComputedStyle($0).getPropertyValue("--macro-data-${className}")`, (style) => { + debugLog('Got style:', style); + resolve(style ? JSON.parse(style) : null); + }); + }); + return promise; + } + + // Function to disconnect the current observer + const disconnectObserver = () => { + if (currentObserver) { + chrome.devtools.inspectedWindow.eval(` + if (window.__styleMacroObserver) { + window.__styleMacroObserver.disconnect(); + window.__styleMacroObserver = null; + } + `); + debugLog('Disconnected mutation observer for element:', currentElementId); + currentObserver = null; + currentElementId = null; + } + }; + + // Function to start observing the currently selected element + const startObserving = () => { + // First disconnect any existing observer + disconnectObserver(); + + // Generate a unique ID for the current element + chrome.devtools.inspectedWindow.eval(` + (function() { + const element = $0; + if (!element || !element.classList) { + return null; + } + + // Generate a unique ID if element doesn't have one + if (!element.__devtoolsId) { + element.__devtoolsId = 'dt-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9); + } + + const elementId = element.__devtoolsId; + + // Create mutation observer + if (window.__styleMacroObserver) { + window.__styleMacroObserver.disconnect(); + } + + window.__styleMacroObserver = new MutationObserver((mutations) => { + for (const mutation of mutations) { + if (mutation.type === 'attributes' && mutation.attributeName === 'class') { + // Notify DevTools that the class has changed via window.postMessage + // (chrome.runtime is not available in page context) + window.postMessage({ + action: 'stylemacro-class-changed', + elementId: elementId + }, '*'); + break; + } + } + }); + + window.__styleMacroObserver.observe(element, { + attributes: true, + attributeFilter: ['class'] + }); + + return elementId; + })(); + `, (result, isException) => { + if (isException) { + debugLog('Error setting up mutation observer:', result); + } else if (result) { + currentElementId = result; + currentObserver = true; // Just track that we have an observer + debugLog('Started observing element:', currentElementId); + } + }); + }; + + let update = () => { + debugLog('Starting update...'); + chrome.devtools.inspectedWindow.eval('$0.getAttribute("class")', (className) => { + debugLog('Got className:', className); + + // Handle the async operations outside the eval callback + (async () => { + if (typeof className !== 'string') { + sidebar.setObject({}); + return; + } + + let staticMacroHashes = [...className.matchAll(/-macro-static-([^\s]+)/g)].map(m => m[1]); + let dynamicMacroHashes = [...className.matchAll(/-macro-dynamic-([^\s]+)/g)].map(m => m[1]); + debugLog('Static macro hashes:', staticMacroHashes); + debugLog('Dynamic macro hashes:', dynamicMacroHashes); + + // Get static macro data (async from CSS) + let staticMacros = staticMacroHashes.map(macro => getMacroData(macro)); + + debugLog('Waiting for', staticMacros.length, 'static macros...'); + let staticResults = await Promise.all(staticMacros); + + // Get dynamic macro data (sync from local storage) + let dynamicResults = dynamicMacroHashes.map(hash => getDynamicMacroData(hash)); + + // Combine results + let results = [...staticResults, ...dynamicResults]; + debugLog('Results:', results); + + // Filter out null results (missing data) + results = results.filter(r => r != null); + debugLog('Filtered results:', results); + + if (results.length === 0) { + sidebar.setObject({}); + } else if (results.length === 1) { + sidebar.setObject(results[0].style ?? {}, results[0].loc); + } else { + let seenProperties = new Set(); + for (let i = results.length - 1; i >= 0; i--) { + for (let key in results[i].style) { + if (seenProperties.has(key)) { + delete results[i].style[key]; + } else { + seenProperties.add(key); + } + } + } + + let res = {}; + for (let result of results) { + res[result.loc] = result.style; + } + sidebar.setObject(res); + } + })(); + }); + }; + + chrome.devtools.panels.elements.onSelectionChanged.addListener(() => { + debugLog('Element selection changed'); + // Start observing the newly selected element + startObserving(); + // Update the panel with the new element's macros + update(); + }); + + // Initial observation when the panel is first opened + startObserving(); + + // Cleanup stale macro data every 5 minutes + const CLEANUP_INTERVAL = 1000 * 60 * 5; + setInterval(() => { + if (macroData.size === 0) { + return; + } + + debugLog('Running macro data cleanup, checking', macroData.size, 'macros...'); + const hashes = Array.from(macroData.keys()); + + // Check all hashes in a single eval for efficiency + const checkScript = ` + (function() { + const hashes = ${JSON.stringify(hashes)}; + const results = {}; + for (const hash of hashes) { + results[hash] = !!document.querySelector('.-macro-dynamic-' + hash); + } + return results; + })(); + `; + + chrome.devtools.inspectedWindow.eval(checkScript, (results, isException) => { + if (isException) { + debugLog('Error during cleanup:', results); + return; + } + + let removedCount = 0; + for (const hash in results) { + if (!results[hash]) { + debugLog('Removing stale macro:', hash); + macroData.delete(hash); + removedCount++; + } + } + + if (removedCount > 0) { + debugLog(`Cleaned up ${removedCount} stale macro(s). Remaining: ${macroData.size}`); + } else { + debugLog('No stale macros found.'); + } + }); + }, CLEANUP_INTERVAL); +}); diff --git a/packages/dev/style-macro-chrome-plugin/src/devtools.html b/packages/dev/style-macro-chrome-plugin/src/devtools.html new file mode 100644 index 00000000000..6f5f400e09b --- /dev/null +++ b/packages/dev/style-macro-chrome-plugin/src/devtools.html @@ -0,0 +1,7 @@ + + + + Devtools! + + + diff --git a/packages/dev/style-macro-chrome-plugin/src/icons/128.png b/packages/dev/style-macro-chrome-plugin/src/icons/128.png new file mode 100644 index 0000000000000000000000000000000000000000..a0a1377e1a933483bdcef461f0c3813bad037c80 GIT binary patch literal 10103 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 R5a3QaKtV=Tx>C{%@;{S}i6;O6 literal 0 HcmV?d00001 diff --git a/packages/dev/style-macro-chrome-plugin/src/icons/16.png b/packages/dev/style-macro-chrome-plugin/src/icons/16.png new file mode 100644 index 0000000000000000000000000000000000000000..41a22d0a311ca53a261ed94b5efab5669b7661bf GIT binary patch literal 877 zcmV-z1CsoSP)vUY3L+}6s7O_Vl*+BBleRJB0ig+FJGL|S z%$)3dy1_W62SUcOP`-(0>LUYTET?ZyuF zs(*TQ^IpJSdddKRCsuC>0FcOWOMK_tnK}T}^|S&2KaD;jZXP-;sw6`E^P;2NTy1KS zpdQNKuhXGH5F=wMX2TfvxkHQBuXQt4E4ws475+De%}B)UP=-4)>S!WOiy~_!7y|$# zj!g{!z+_{GQTToY05@|-jQ%iHk7Mr3i?QSS*1&y(1HC_;ct`<&1IuOpzZO)FW6a#f zKUCsUPS49&868co<3tB&GuZBSiVVvf)JG zze`_utVr4sy7aRhD;tPXqL9{7eiUJ)+4jp#tFDNm*AsUHp~Wc4G|bxmYB!Q;4FG78 z33z2>kOF{6Db{VzTeF<(o*(SD5{n4}0PUugb#0DM-u~EfcANhg3<$K7AVlqnJt8;& zfH2g4?eIMSNO4bJyR+5sY?q%ub+%okF>Q<=0WXzglF#IxeLAhqPp9M>09&UY`9M4&-B%PO#on00000NkvXXu0mjf D0OFE2 literal 0 HcmV?d00001 diff --git a/packages/dev/style-macro-chrome-plugin/src/icons/32.png b/packages/dev/style-macro-chrome-plugin/src/icons/32.png new file mode 100644 index 0000000000000000000000000000000000000000..493110735d24a98300418e84e5e0b40093a7e0b5 GIT binary patch literal 1987 zcmV;!2R!(RP)G3{hXJ>XE{eivAuGhqs+VgAfne#s1J@;P9Fbn`dOI7nz01g8P;r~m00FDhN zhmHdPWf%rps+x}zo`2G_^UG=ep{+V`Iz0=u#>o=uqZ3#&*e?)ORX9bq^sQXuAE<9c z&So!>)pI!^-+x_6zW8!b7sb~GlS5BY&Az6?gy#<}`NQvIieYREb-ZHq7WVw@RCGx^ z5}Z$_*I<%8OB&e=yT8es`D#2qHM#FOpDv2upqhP6BZ24kv)qRD^BOW!eQW~XKK=GR z9cMKi2L@v*fRs*A8r|B;PCvWfWtPcZ?2X2sKN=wbLiV+vb5%Aqm&%=A$>ecxC?0)t zG9^T0wJ7JJE!nGCxynH(2v_>7-#Yn6!EA?Jy~+xpjQ{{e)1}Rthqm^$sfIzas*X*=H@sW=dZbxh!f{>zpqhP6 zMyT^opXr>8N5KF3mAtO$EM3TDj%=uLvXK}jYpb#JyE{QFbix^^^P6>)q2b7heMf5C zj3u|(%W(kk?9&I3aC-p&;U~TdvXIOH;Bh07Oy#GM%m~pzA!hac@H_DR@<(#0r9mO# zc#QJ|{pC8=rUv(pTDLUo900!b;olQx8G4}sG_GsSANkoHjEzUA_WRdRPA3llHt+5y zpl3ynFxELbQ)3f3`hhlDJ@;|3#ciM7(9ALwD^MSs!1_1bGxQt@$FoE8ilGqEb2;meR?vB4s31$wQ?S#>8x~URy(gOv`crrDI46KD zeLd2l6TguRLO3)3g(Oq;#;K1o&5JzrYcF=iUVrC|Rm`M(1O1;Er(f?9Wib_0a_Nwg zONXRX!hYfWM_C&U7sc8@KhUO_ZLJ;|x(mi~=N;Xhb^y54yt*W?m`3p4!@Hc`b!+t} z_wKBIc+-9S?@xT7ur|iGb=$_`pixyV_m}P-k*CyRsmrUdZs=MO2Sp5+o%c61Cjiuy zR|f!oBGvjsL;+m2z^+y97v6nO7B5}4t!k>3moD~CJM1)BS?3M-Yy3rr6l()%38nRc zVf#!4ih!j7V9S*Ya>x5!MWCE*Yp>`W07Qe}y2jpRZ2yW)K7SGWA6#Jr5Ci~kWCs94DN#@i2#?jcv-25ey$(4( z79qN(SNtz38u}ZWi^&lHcqc9{I+xR>HowQxz}bpdaz)n>mE^nGiTP}}VC3pqW^pCs ziGmhg9P~I0!(gMgClZxp&J-MiYPpLM0sxb$0oH1@Zx1+1%5EhDA4H~eqgg4Z=sKq4 zg5N)E9kxs**tf;4Q=(*NhTGiFqZO zQS~`GD|D^4|N3Z2@5PMh*tho>yw`5%o9cpcrtZ$9&-Y(f0E7vEWADZ@?t)=RhN=p8cIxF{yiKi4CeY&Ik!@@e0l-jINqF^m5WwNt z$LWpn=f!_s zwgqX5q literal 0 HcmV?d00001 diff --git a/packages/dev/style-macro-chrome-plugin/src/icons/48.png b/packages/dev/style-macro-chrome-plugin/src/icons/48.png new file mode 100644 index 0000000000000000000000000000000000000000..6794ef2da835ad9fba232dee798d4443914188a6 GIT binary patch literal 3413 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 literal 0 HcmV?d00001 diff --git a/packages/dev/style-macro-chrome-plugin/src/icons/96.png b/packages/dev/style-macro-chrome-plugin/src/icons/96.png new file mode 100644 index 0000000000000000000000000000000000000000..b12d2c4a2f0104c313d0d3186e8e90d552154d85 GIT binary patch literal 7532 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 Date: Tue, 27 Jan 2026 17:23:44 -0800 Subject: [PATCH 2/2] feat: Add `render` prop to allow customizing DOM element (#9499) * prototype: Add render prop to allow customizing DOM element * Implement all components * Omit from Spectrum * Add render props as a second argument * review comments --- .../accordion/chromatic/Accordion.stories.tsx | 4 +- .../accordion/src/Accordion.tsx | 6 +- .../@react-spectrum/dropzone/src/DropZone.tsx | 2 +- packages/@react-spectrum/s2/src/Accordion.tsx | 2 +- .../@react-spectrum/s2/src/ActionButton.tsx | 2 +- .../@react-spectrum/s2/src/Breadcrumbs.tsx | 4 +- packages/@react-spectrum/s2/src/Button.tsx | 4 +- packages/@react-spectrum/s2/src/Calendar.tsx | 2 +- packages/@react-spectrum/s2/src/Card.tsx | 2 +- packages/@react-spectrum/s2/src/CardView.tsx | 2 +- packages/@react-spectrum/s2/src/Checkbox.tsx | 2 +- .../@react-spectrum/s2/src/CheckboxGroup.tsx | 2 +- packages/@react-spectrum/s2/src/ColorArea.tsx | 2 +- .../@react-spectrum/s2/src/ColorField.tsx | 2 +- .../@react-spectrum/s2/src/ColorSlider.tsx | 2 +- .../@react-spectrum/s2/src/ColorSwatch.tsx | 2 +- .../@react-spectrum/s2/src/ColorWheel.tsx | 2 +- packages/@react-spectrum/s2/src/ComboBox.tsx | 4 +- .../@react-spectrum/s2/src/CustomDialog.tsx | 2 +- packages/@react-spectrum/s2/src/DateField.tsx | 2 +- .../@react-spectrum/s2/src/DatePicker.tsx | 2 +- .../s2/src/DateRangePicker.tsx | 2 +- packages/@react-spectrum/s2/src/Dialog.tsx | 2 +- .../@react-spectrum/s2/src/Disclosure.tsx | 4 +- packages/@react-spectrum/s2/src/Divider.tsx | 2 +- packages/@react-spectrum/s2/src/DropZone.tsx | 2 +- packages/@react-spectrum/s2/src/Field.tsx | 6 +- packages/@react-spectrum/s2/src/Form.tsx | 2 +- .../s2/src/FullscreenDialog.tsx | 2 +- packages/@react-spectrum/s2/src/Link.tsx | 2 +- packages/@react-spectrum/s2/src/Menu.tsx | 6 +- packages/@react-spectrum/s2/src/Meter.tsx | 2 +- packages/@react-spectrum/s2/src/Modal.tsx | 2 +- .../@react-spectrum/s2/src/NumberField.tsx | 2 +- packages/@react-spectrum/s2/src/Picker.tsx | 6 +- packages/@react-spectrum/s2/src/Popover.tsx | 3 +- .../@react-spectrum/s2/src/ProgressBar.tsx | 2 +- .../@react-spectrum/s2/src/ProgressCircle.tsx | 2 +- packages/@react-spectrum/s2/src/Radio.tsx | 2 +- .../@react-spectrum/s2/src/RadioGroup.tsx | 2 +- .../@react-spectrum/s2/src/RangeCalendar.tsx | 2 +- .../@react-spectrum/s2/src/SearchField.tsx | 2 +- .../@react-spectrum/s2/src/SelectBoxGroup.tsx | 2 +- packages/@react-spectrum/s2/src/Slider.tsx | 2 +- packages/@react-spectrum/s2/src/Switch.tsx | 2 +- packages/@react-spectrum/s2/src/TableView.tsx | 10 +- packages/@react-spectrum/s2/src/Tabs.tsx | 8 +- .../@react-spectrum/s2/src/TabsPicker.tsx | 4 +- packages/@react-spectrum/s2/src/TagGroup.tsx | 4 +- packages/@react-spectrum/s2/src/TextField.tsx | 2 +- packages/@react-spectrum/s2/src/TimeField.tsx | 2 +- packages/@react-spectrum/s2/src/Toast.tsx | 2 +- .../@react-spectrum/s2/src/ToggleButton.tsx | 2 +- .../s2/src/ToggleButtonGroup.tsx | 2 +- packages/@react-spectrum/s2/src/Tooltip.tsx | 2 +- packages/@react-spectrum/s2/src/TreeView.tsx | 4 +- .../@react-spectrum/tree/src/TreeView.tsx | 4 +- .../dev/s2-docs/src/ComponentCardView.tsx | 2 +- packages/dev/s2-docs/src/PropTable.tsx | 2 +- packages/dev/s2-docs/src/Tabs.tsx | 8 +- .../react-aria-components/src/Breadcrumbs.tsx | 15 ++- packages/react-aria-components/src/Button.tsx | 7 +- .../react-aria-components/src/Calendar.tsx | 46 ++++---- .../react-aria-components/src/Checkbox.tsx | 13 ++- .../react-aria-components/src/ColorArea.tsx | 5 +- .../react-aria-components/src/ColorField.tsx | 3 +- .../react-aria-components/src/ColorSlider.tsx | 3 +- .../react-aria-components/src/ColorSwatch.tsx | 3 +- .../src/ColorSwatchPicker.tsx | 2 + .../react-aria-components/src/ColorThumb.tsx | 6 +- .../react-aria-components/src/ColorWheel.tsx | 7 +- .../react-aria-components/src/ComboBox.tsx | 3 +- .../react-aria-components/src/DateField.tsx | 9 +- .../react-aria-components/src/DatePicker.tsx | 5 +- packages/react-aria-components/src/Dialog.tsx | 9 +- .../react-aria-components/src/Disclosure.tsx | 13 ++- .../react-aria-components/src/DropZone.tsx | 6 +- packages/react-aria-components/src/Form.tsx | 8 +- .../react-aria-components/src/GridList.tsx | 50 +++++---- packages/react-aria-components/src/Group.tsx | 19 ++-- packages/react-aria-components/src/Header.tsx | 12 +- .../react-aria-components/src/Heading.tsx | 8 +- packages/react-aria-components/src/Input.tsx | 5 +- .../react-aria-components/src/Keyboard.tsx | 6 +- packages/react-aria-components/src/Label.tsx | 7 +- packages/react-aria-components/src/Link.tsx | 25 +++-- .../react-aria-components/src/ListBox.tsx | 45 ++++---- packages/react-aria-components/src/Menu.tsx | 28 +++-- packages/react-aria-components/src/Meter.tsx | 5 +- packages/react-aria-components/src/Modal.tsx | 9 +- .../react-aria-components/src/NumberField.tsx | 3 +- .../src/OverlayArrow.tsx | 5 +- .../react-aria-components/src/Popover.tsx | 5 +- .../react-aria-components/src/ProgressBar.tsx | 5 +- .../react-aria-components/src/RadioGroup.tsx | 11 +- .../react-aria-components/src/SearchField.tsx | 5 +- packages/react-aria-components/src/Select.tsx | 11 +- .../react-aria-components/src/Separator.tsx | 13 ++- .../src/SharedElementTransition.tsx | 7 +- packages/react-aria-components/src/Slider.tsx | 16 +-- packages/react-aria-components/src/Switch.tsx | 21 ++-- packages/react-aria-components/src/Table.tsx | 69 ++++++------ packages/react-aria-components/src/Tabs.tsx | 27 ++--- .../react-aria-components/src/TagGroup.tsx | 27 +++-- packages/react-aria-components/src/Text.tsx | 7 +- .../react-aria-components/src/TextArea.tsx | 5 +- .../react-aria-components/src/TextField.tsx | 7 +- packages/react-aria-components/src/Toast.tsx | 26 +++-- .../src/ToggleButton.tsx | 7 +- .../src/ToggleButtonGroup.tsx | 5 +- .../react-aria-components/src/Toolbar.tsx | 5 +- .../react-aria-components/src/Tooltip.tsx | 5 +- packages/react-aria-components/src/Tree.tsx | 35 +++--- packages/react-aria-components/src/utils.tsx | 104 ++++++++++++++++-- .../stories/Button.stories.tsx | 8 ++ .../stories/Calendar.stories.tsx | 2 +- .../stories/Menu.stories.tsx | 33 +++++- .../test/Breadcrumbs.test.js | 9 ++ .../react-aria-components/test/Button.test.js | 26 +++++ .../test/Calendar.test.js | 17 +++ .../test/Checkbox.test.js | 7 ++ .../test/CheckboxGroup.test.js | 6 + .../test/ColorArea.test.js | 10 ++ .../test/ColorField.test.js | 6 + .../test/ColorSlider.test.js | 14 +++ .../test/ColorSwatch.test.js | 6 + .../test/ColorWheel.test.js | 8 ++ .../test/ComboBox.test.js | 6 + .../test/DateField.test.js | 19 ++++ .../test/DatePicker.test.js | 6 + .../test/DateRangePicker.test.js | 6 + .../test/Disclosure.test.js | 17 +++ .../test/DropZone.test.js | 12 ++ .../react-aria-components/test/Form.test.js | 10 ++ .../test/GridList.test.js | 13 +++ .../react-aria-components/test/Group.test.tsx | 6 + .../react-aria-components/test/Link.test.js | 13 +++ .../test/ListBox.test.js | 28 +++++ .../react-aria-components/test/Menu.test.tsx | 28 +++++ .../react-aria-components/test/Meter.test.js | 6 + .../test/NumberField.test.js | 6 + .../test/Popover.test.js | 8 ++ .../test/ProgressBar.test.js | 6 + .../test/RadioGroup.test.js | 13 +++ .../test/RangeCalendar.test.tsx | 17 +++ .../test/SearchField.test.js | 6 + .../react-aria-components/test/Select.test.js | 6 + .../test/Separator.test.js | 6 + .../react-aria-components/test/Slider.test.js | 14 +++ .../react-aria-components/test/Switch.test.js | 7 ++ .../react-aria-components/test/Table.test.js | 34 ++++++ .../react-aria-components/test/Tabs.test.js | 40 +++++++ .../test/TagGroup.test.js | 16 +++ .../test/TextField.test.js | 6 + .../test/TimeField.test.js | 19 ++++ .../test/ToggleButton.test.js | 6 + .../test/ToggleButtonGroup.test.js | 6 + .../test/Toolbar.test.tsx | 10 ++ .../test/Tooltip.test.js | 8 ++ .../react-aria-components/test/Tree.test.tsx | 10 ++ 160 files changed, 1141 insertions(+), 413 deletions(-) diff --git a/packages/@react-spectrum/accordion/chromatic/Accordion.stories.tsx b/packages/@react-spectrum/accordion/chromatic/Accordion.stories.tsx index e496e26a90c..a492ca26c44 100644 --- a/packages/@react-spectrum/accordion/chromatic/Accordion.stories.tsx +++ b/packages/@react-spectrum/accordion/chromatic/Accordion.stories.tsx @@ -22,9 +22,9 @@ const meta: Meta = { export default meta; -export type AccordionStory = StoryObj; +export type AccordionStory = StoryObj>; -export const Template = (args: SpectrumAccordionProps): JSX.Element => ( +export const Template = (args: Partial): JSX.Element => ( diff --git a/packages/@react-spectrum/accordion/src/Accordion.tsx b/packages/@react-spectrum/accordion/src/Accordion.tsx index 1344ca0cff1..e8233f1bc74 100644 --- a/packages/@react-spectrum/accordion/src/Accordion.tsx +++ b/packages/@react-spectrum/accordion/src/Accordion.tsx @@ -20,7 +20,7 @@ import styles from '@adobe/spectrum-css-temp/components/accordion/vars.css'; import {useLocale} from '@react-aria/i18n'; import {useProviderProps} from '@react-spectrum/provider'; -export interface SpectrumAccordionProps extends Omit, StyleProps, DOMProps { +export interface SpectrumAccordionProps extends Omit, StyleProps, DOMProps { /** Whether the Accordion should be displayed with a quiet style. */ isQuiet?: boolean, /** The disclosures within the accordion group. */ @@ -47,7 +47,7 @@ export const Accordion = /*#__PURE__*/(forwardRef as forwardRefType)(function Ac ); }); -export interface SpectrumDisclosureProps extends Omit, AriaLabelingProps, StyleProps { +export interface SpectrumDisclosureProps extends Omit, AriaLabelingProps, StyleProps { /** Whether the Disclosure should be displayed with a quiet style. */ isQuiet?: boolean, /** The contents of the disclosure. The first child should be the header, and the second child should be the panel. */ @@ -76,7 +76,7 @@ export const Disclosure = /*#__PURE__*/(forwardRef as forwardRefType)(function D ); }); -export interface SpectrumDisclosurePanelProps extends Omit, DOMProps, AriaLabelingProps, StyleProps { +export interface SpectrumDisclosurePanelProps extends Omit, DOMProps, AriaLabelingProps, StyleProps { /** The contents of the accordion panel. */ children: React.ReactNode } diff --git a/packages/@react-spectrum/dropzone/src/DropZone.tsx b/packages/@react-spectrum/dropzone/src/DropZone.tsx index 1c272755267..cdfb860dc6b 100644 --- a/packages/@react-spectrum/dropzone/src/DropZone.tsx +++ b/packages/@react-spectrum/dropzone/src/DropZone.tsx @@ -20,7 +20,7 @@ import React, {ReactNode} from 'react'; import styles from '@adobe/spectrum-css-temp/components/dropzone/vars.css'; import {useLocalizedStringFormatter} from '@react-aria/i18n'; -export interface SpectrumDropZoneProps extends Omit, DOMProps, StyleProps, AriaLabelingProps { +export interface SpectrumDropZoneProps extends Omit, DOMProps, StyleProps, AriaLabelingProps { /** The content to display in the drop zone. */ children: ReactNode, /** Whether the drop zone has been filled. */ diff --git a/packages/@react-spectrum/s2/src/Accordion.tsx b/packages/@react-spectrum/s2/src/Accordion.tsx index 03c9373946a..c3e15cffea2 100644 --- a/packages/@react-spectrum/s2/src/Accordion.tsx +++ b/packages/@react-spectrum/s2/src/Accordion.tsx @@ -122,7 +122,7 @@ export interface AccordionItemRenderProps { state: AccordionItemState } -export interface AccordionItemProps extends Omit, 'className' | 'style'>, SlotProps, StyleProps { +export interface AccordionItemProps extends Omit, 'className' | 'style' | 'render'>, SlotProps, StyleProps { /** * The size of the accordion item. * @default 'M' diff --git a/packages/@react-spectrum/s2/src/ActionButton.tsx b/packages/@react-spectrum/s2/src/ActionButton.tsx index 4ed24b9e0d9..4753def4f4a 100644 --- a/packages/@react-spectrum/s2/src/ActionButton.tsx +++ b/packages/@react-spectrum/s2/src/ActionButton.tsx @@ -59,7 +59,7 @@ interface ActionGroupItemStyleProps { isJustified?: boolean } -export interface ActionButtonProps extends Omit, StyleProps, ActionButtonStyleProps { +export interface ActionButtonProps extends Omit, StyleProps, ActionButtonStyleProps { /** The content to display in the ActionButton. */ children: ReactNode } diff --git a/packages/@react-spectrum/s2/src/Breadcrumbs.tsx b/packages/@react-spectrum/s2/src/Breadcrumbs.tsx index 033fa2fa295..c78b6c53ddc 100644 --- a/packages/@react-spectrum/s2/src/Breadcrumbs.tsx +++ b/packages/@react-spectrum/s2/src/Breadcrumbs.tsx @@ -63,7 +63,7 @@ interface BreadcrumbsStyleProps { // TODO: showRoot?: boolean, } -export interface BreadcrumbsProps extends Omit, 'children' | 'style' | 'className' | keyof GlobalDOMAttributes>, BreadcrumbsStyleProps, StyleProps { +export interface BreadcrumbsProps extends Omit, 'children' | 'style' | 'className' | 'render' | keyof GlobalDOMAttributes>, BreadcrumbsStyleProps, StyleProps { /** The children of the Breadcrumbs. */ children: ReactNode | ((item: T) => ReactNode) } @@ -296,7 +296,7 @@ const heading = style({ fontWeight: 'extra-bold' }); -export interface BreadcrumbProps extends Omit, LinkDOMProps { +export interface BreadcrumbProps extends Omit, LinkDOMProps { /** The children of the breadcrumb item. */ children: ReactNode } diff --git a/packages/@react-spectrum/s2/src/Button.tsx b/packages/@react-spectrum/s2/src/Button.tsx index a9b9db869ec..412f4ee66a0 100644 --- a/packages/@react-spectrum/s2/src/Button.tsx +++ b/packages/@react-spectrum/s2/src/Button.tsx @@ -52,12 +52,12 @@ interface ButtonStyleProps { staticColor?: 'white' | 'black' | 'auto' } -export interface ButtonProps extends Omit, StyleProps, ButtonStyleProps { +export interface ButtonProps extends Omit, StyleProps, ButtonStyleProps { /** The content to display in the Button. */ children: ReactNode } -export interface LinkButtonProps extends Omit, StyleProps, ButtonStyleProps { +export interface LinkButtonProps extends Omit, StyleProps, ButtonStyleProps { /** The content to display in the Button. */ children: ReactNode } diff --git a/packages/@react-spectrum/s2/src/Calendar.tsx b/packages/@react-spectrum/s2/src/Calendar.tsx index f557059a519..57736226afd 100644 --- a/packages/@react-spectrum/s2/src/Calendar.tsx +++ b/packages/@react-spectrum/s2/src/Calendar.tsx @@ -55,7 +55,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps'; export interface CalendarProps - extends Omit, 'visibleDuration' | 'style' | 'className' | 'styles' | 'children' | keyof GlobalDOMAttributes>, + extends Omit, 'visibleDuration' | 'style' | 'className' | 'render' | 'styles' | 'children' | keyof GlobalDOMAttributes>, StyleProps { /** * The error message to display when the calendar is invalid. diff --git a/packages/@react-spectrum/s2/src/Card.tsx b/packages/@react-spectrum/s2/src/Card.tsx index 7ad9aeaf49e..2d9d08d9479 100644 --- a/packages/@react-spectrum/s2/src/Card.tsx +++ b/packages/@react-spectrum/s2/src/Card.tsx @@ -36,7 +36,7 @@ interface CardRenderProps { size: 'XS' | 'S' | 'M' | 'L' | 'XL' } -export interface CardProps extends Omit, StyleProps { +export interface CardProps extends Omit, StyleProps { /** The children of the Card. */ children: ReactNode | ((renderProps: CardRenderProps) => ReactNode), /** diff --git a/packages/@react-spectrum/s2/src/CardView.tsx b/packages/@react-spectrum/s2/src/CardView.tsx index 2023a8c0d95..b71b98d731f 100644 --- a/packages/@react-spectrum/s2/src/CardView.tsx +++ b/packages/@react-spectrum/s2/src/CardView.tsx @@ -34,7 +34,7 @@ import {useDOMRef} from '@react-spectrum/utils'; import {useEffectEvent, useLayoutEffect, useResizeObserver} from '@react-aria/utils'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface CardViewProps extends Omit, 'layout' | 'keyboardNavigationBehavior' | 'selectionBehavior' | 'className' | 'style' | 'isLoading' | keyof GlobalDOMAttributes>, UnsafeStyles { +export interface CardViewProps extends Omit, 'layout' | 'keyboardNavigationBehavior' | 'selectionBehavior' | 'className' | 'style' | 'render' | 'isLoading' | keyof GlobalDOMAttributes>, UnsafeStyles { /** * The layout of the cards. * @default 'grid' diff --git a/packages/@react-spectrum/s2/src/Checkbox.tsx b/packages/@react-spectrum/s2/src/Checkbox.tsx index 194c240ad13..0f4830f98b9 100644 --- a/packages/@react-spectrum/s2/src/Checkbox.tsx +++ b/packages/@react-spectrum/s2/src/Checkbox.tsx @@ -36,7 +36,7 @@ interface CheckboxStyleProps { interface RenderProps extends CheckboxRenderProps, CheckboxStyleProps {} -export interface CheckboxProps extends Omit, StyleProps, CheckboxStyleProps { +export interface CheckboxProps extends Omit, StyleProps, CheckboxStyleProps { /** The label for the element. */ children?: ReactNode } diff --git a/packages/@react-spectrum/s2/src/CheckboxGroup.tsx b/packages/@react-spectrum/s2/src/CheckboxGroup.tsx index 94e8d1edb1b..8a5d412221b 100644 --- a/packages/@react-spectrum/s2/src/CheckboxGroup.tsx +++ b/packages/@react-spectrum/s2/src/CheckboxGroup.tsx @@ -25,7 +25,7 @@ import {style} from '../style' with {type: 'macro'}; import {useDOMRef} from '@react-spectrum/utils'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface CheckboxGroupProps extends Omit, StyleProps, SpectrumLabelableProps, HelpTextProps { +export interface CheckboxGroupProps extends Omit, StyleProps, SpectrumLabelableProps, HelpTextProps { /** * The size of the Checkboxes in the CheckboxGroup. * diff --git a/packages/@react-spectrum/s2/src/ColorArea.tsx b/packages/@react-spectrum/s2/src/ColorArea.tsx index 6c401b3efa8..82defe7c503 100644 --- a/packages/@react-spectrum/s2/src/ColorArea.tsx +++ b/packages/@react-spectrum/s2/src/ColorArea.tsx @@ -24,7 +24,7 @@ import {style} from '../style' with {type: 'macro'}; import {useDOMRef} from '@react-spectrum/utils'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface ColorAreaProps extends Omit, StyleProps {} +export interface ColorAreaProps extends Omit, StyleProps {} export const ColorAreaContext = createContext, DOMRefValue>>(null); diff --git a/packages/@react-spectrum/s2/src/ColorField.tsx b/packages/@react-spectrum/s2/src/ColorField.tsx index 1addb1c9f65..ead7b7ed870 100644 --- a/packages/@react-spectrum/s2/src/ColorField.tsx +++ b/packages/@react-spectrum/s2/src/ColorField.tsx @@ -26,7 +26,7 @@ import {style} from '../style' with {type: 'macro'}; import {TextFieldRef} from '@react-types/textfield'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface ColorFieldProps extends Omit, StyleProps, SpectrumLabelableProps, HelpTextProps, Pick { +export interface ColorFieldProps extends Omit, StyleProps, SpectrumLabelableProps, HelpTextProps, Pick { /** * The size of the color field. * diff --git a/packages/@react-spectrum/s2/src/ColorSlider.tsx b/packages/@react-spectrum/s2/src/ColorSlider.tsx index d9a78172a0e..fad78a3a778 100644 --- a/packages/@react-spectrum/s2/src/ColorSlider.tsx +++ b/packages/@react-spectrum/s2/src/ColorSlider.tsx @@ -27,7 +27,7 @@ import {style} from '../style' with {type: 'macro'}; import {useDOMRef} from '@react-spectrum/utils'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface ColorSliderProps extends Omit, Pick, StyleProps { +export interface ColorSliderProps extends Omit, Pick, StyleProps { label?: string } diff --git a/packages/@react-spectrum/s2/src/ColorSwatch.tsx b/packages/@react-spectrum/s2/src/ColorSwatch.tsx index 99a38464f9d..de34fc356e4 100644 --- a/packages/@react-spectrum/s2/src/ColorSwatch.tsx +++ b/packages/@react-spectrum/s2/src/ColorSwatch.tsx @@ -24,7 +24,7 @@ import {style} from '../style' with {type: 'macro'}; import {useDOMRef} from '@react-spectrum/utils'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface ColorSwatchProps extends Omit, UnsafeStyles { +export interface ColorSwatchProps extends Omit, UnsafeStyles { /** * The size of the ColorSwatch. * @default 'M' diff --git a/packages/@react-spectrum/s2/src/ColorWheel.tsx b/packages/@react-spectrum/s2/src/ColorWheel.tsx index 57d63dec7ff..8459451dce5 100644 --- a/packages/@react-spectrum/s2/src/ColorWheel.tsx +++ b/packages/@react-spectrum/s2/src/ColorWheel.tsx @@ -24,7 +24,7 @@ import {StyleProps} from './style-utils'; import {useDOMRef} from '@react-spectrum/utils'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface ColorWheelProps extends Omit, StyleProps { +export interface ColorWheelProps extends Omit, StyleProps { /** * @default 192 */ diff --git a/packages/@react-spectrum/s2/src/ComboBox.tsx b/packages/@react-spectrum/s2/src/ComboBox.tsx index ab2348328b6..d3cd25f882f 100644 --- a/packages/@react-spectrum/s2/src/ComboBox.tsx +++ b/packages/@react-spectrum/s2/src/ComboBox.tsx @@ -79,7 +79,7 @@ export interface ComboboxStyleProps { size?: 'S' | 'M' | 'L' | 'XL' } export interface ComboBoxProps extends - Omit, 'children' | 'style' | 'className' | 'defaultFilter' | 'allowsEmptyCollection' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>, + Omit, 'children' | 'style' | 'className' | 'render' | 'defaultFilter' | 'allowsEmptyCollection' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>, ComboboxStyleProps, StyleProps, SpectrumLabelableProps, @@ -369,7 +369,7 @@ export const ComboBox = /*#__PURE__*/ (forwardRef as forwardRefType)(function Co ); }); -export interface ComboBoxItemProps extends Omit, StyleProps { +export interface ComboBoxItemProps extends Omit, StyleProps { children: ReactNode } diff --git a/packages/@react-spectrum/s2/src/CustomDialog.tsx b/packages/@react-spectrum/s2/src/CustomDialog.tsx index 3520f8d730b..b06db9c38f0 100644 --- a/packages/@react-spectrum/s2/src/CustomDialog.tsx +++ b/packages/@react-spectrum/s2/src/CustomDialog.tsx @@ -18,7 +18,7 @@ import {Modal} from './Modal'; import {style} from '../style' with {type: 'macro'}; import {useDOMRef} from '@react-spectrum/utils'; -export interface CustomDialogProps extends Omit, StyleProps { +export interface CustomDialogProps extends Omit, StyleProps { /** * The size of the Dialog. */ diff --git a/packages/@react-spectrum/s2/src/DateField.tsx b/packages/@react-spectrum/s2/src/DateField.tsx index a42d2a96ec7..cc9c65a05bf 100644 --- a/packages/@react-spectrum/s2/src/DateField.tsx +++ b/packages/@react-spectrum/s2/src/DateField.tsx @@ -30,7 +30,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps'; export interface DateFieldProps extends - Omit, 'children' | 'className' | 'style' | keyof GlobalDOMAttributes>, + Omit, 'children' | 'className' | 'style' | 'render' | keyof GlobalDOMAttributes>, StyleProps, SpectrumLabelableProps, HelpTextProps { diff --git a/packages/@react-spectrum/s2/src/DatePicker.tsx b/packages/@react-spectrum/s2/src/DatePicker.tsx index b98a99ef1ad..ab44172d92c 100644 --- a/packages/@react-spectrum/s2/src/DatePicker.tsx +++ b/packages/@react-spectrum/s2/src/DatePicker.tsx @@ -41,7 +41,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps'; export interface DatePickerProps extends - Omit, 'children' | 'className' | 'style' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>, + Omit, 'children' | 'className' | 'style' | 'render' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>, Pick, 'createCalendar' | 'pageBehavior' | 'firstDayOfWeek' | 'isDateUnavailable'>, Pick, StyleProps, diff --git a/packages/@react-spectrum/s2/src/DateRangePicker.tsx b/packages/@react-spectrum/s2/src/DateRangePicker.tsx index 497d414f631..6ed09210ce6 100644 --- a/packages/@react-spectrum/s2/src/DateRangePicker.tsx +++ b/packages/@react-spectrum/s2/src/DateRangePicker.tsx @@ -33,7 +33,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps'; export interface DateRangePickerProps extends - Omit, 'children' | 'className' | 'style' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>, + Omit, 'children' | 'className' | 'style' | 'render' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>, Pick, 'createCalendar' | 'pageBehavior' | 'firstDayOfWeek' | 'isDateUnavailable'>, Pick, StyleProps, diff --git a/packages/@react-spectrum/s2/src/Dialog.tsx b/packages/@react-spectrum/s2/src/Dialog.tsx index 0a2cd84ddf9..4bee6fb7f31 100644 --- a/packages/@react-spectrum/s2/src/Dialog.tsx +++ b/packages/@react-spectrum/s2/src/Dialog.tsx @@ -23,7 +23,7 @@ import {StyleProps} from './style-utils'; import {useDOMRef} from '@react-spectrum/utils'; // TODO: what style overrides should be allowed? -export interface DialogProps extends Omit, StyleProps { +export interface DialogProps extends Omit, StyleProps { /** * Whether the Dialog is dismissible. */ diff --git a/packages/@react-spectrum/s2/src/Disclosure.tsx b/packages/@react-spectrum/s2/src/Disclosure.tsx index 2c93b4c95d6..512cd1f4412 100644 --- a/packages/@react-spectrum/s2/src/Disclosure.tsx +++ b/packages/@react-spectrum/s2/src/Disclosure.tsx @@ -22,7 +22,7 @@ import React, {createContext, forwardRef, ReactNode, useContext} from 'react'; import {useDOMRef} from '@react-spectrum/utils'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface DisclosureProps extends Omit, StyleProps { +export interface DisclosureProps extends Omit, StyleProps { /** * The size of the disclosure. * @default 'M' @@ -295,7 +295,7 @@ export const DisclosureTitle = forwardRef(function DisclosureTitle(props: Disclo ); }); -export interface DisclosurePanelProps extends Omit, UnsafeStyles, DOMProps, AriaLabelingProps { +export interface DisclosurePanelProps extends Omit, UnsafeStyles, DOMProps, AriaLabelingProps { children: React.ReactNode } diff --git a/packages/@react-spectrum/s2/src/Divider.tsx b/packages/@react-spectrum/s2/src/Divider.tsx index ce33d027e63..f7ab78c5929 100644 --- a/packages/@react-spectrum/s2/src/Divider.tsx +++ b/packages/@react-spectrum/s2/src/Divider.tsx @@ -38,7 +38,7 @@ interface DividerSpectrumProps { } // TODO: allow overriding height (only when orientation is vertical)?? -export interface DividerProps extends DividerSpectrumProps, Omit, StyleProps {} +export interface DividerProps extends DividerSpectrumProps, Omit, StyleProps {} export const DividerContext = createContext, DOMRefValue>>(null); diff --git a/packages/@react-spectrum/s2/src/DropZone.tsx b/packages/@react-spectrum/s2/src/DropZone.tsx index 65fc602491d..5f1220fd0e6 100644 --- a/packages/@react-spectrum/s2/src/DropZone.tsx +++ b/packages/@react-spectrum/s2/src/DropZone.tsx @@ -22,7 +22,7 @@ import {useDOMRef} from '@react-spectrum/utils'; import {useLocalizedStringFormatter} from '@react-aria/i18n'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface DropZoneProps extends Omit, UnsafeStyles, DOMProps { +export interface DropZoneProps extends Omit, UnsafeStyles, DOMProps { /** Spectrum-defined styles, returned by the `style()` macro. */ styles?: StylesPropWithHeight, /** The content to display in the drop zone. */ diff --git a/packages/@react-spectrum/s2/src/Field.tsx b/packages/@react-spectrum/s2/src/Field.tsx index 38c9dfda58e..a2144071c59 100644 --- a/packages/@react-spectrum/s2/src/Field.tsx +++ b/packages/@react-spectrum/s2/src/Field.tsx @@ -28,7 +28,7 @@ import {useDOMRef} from '@react-spectrum/utils'; import {useId} from '@react-aria/utils'; import {useLocalizedStringFormatter} from '@react-aria/i18n'; -interface FieldLabelProps extends Omit, StyleProps { +interface FieldLabelProps extends Omit, StyleProps { isDisabled?: boolean, isRequired?: boolean, size?: 'S' | 'M' | 'L' | 'XL', @@ -150,7 +150,7 @@ export const FieldLabel = forwardRef(function FieldLabel(props: FieldLabelProps, ); }); -interface FieldGroupProps extends Omit, UnsafeStyles { +interface FieldGroupProps extends Omit, UnsafeStyles { size?: 'S' | 'M' | 'L' | 'XL', children: ReactNode, styles?: StyleString, @@ -232,7 +232,7 @@ export const FieldGroup = forwardRef(function FieldGroup(props: FieldGroupProps, ); }); -export interface InputProps extends Omit, StyleProps {} +export interface InputProps extends Omit, StyleProps {} export const Input = forwardRef(function Input(props: InputProps, ref: ForwardedRef) { let {UNSAFE_className = '', UNSAFE_style, styles, ...otherProps} = props; diff --git a/packages/@react-spectrum/s2/src/Form.tsx b/packages/@react-spectrum/s2/src/Form.tsx index 3cc39c3b48a..687e0bb4c78 100644 --- a/packages/@react-spectrum/s2/src/Form.tsx +++ b/packages/@react-spectrum/s2/src/Form.tsx @@ -30,7 +30,7 @@ interface FormStyleProps extends Omit, StyleProps { +export interface FormProps extends FormStyleProps, Omit, StyleProps { children: ReactNode } diff --git a/packages/@react-spectrum/s2/src/FullscreenDialog.tsx b/packages/@react-spectrum/s2/src/FullscreenDialog.tsx index cf293ee72a5..12ff5a60641 100644 --- a/packages/@react-spectrum/s2/src/FullscreenDialog.tsx +++ b/packages/@react-spectrum/s2/src/FullscreenDialog.tsx @@ -21,7 +21,7 @@ import {StyleProps} from './style-utils'; import {useDOMRef} from '@react-spectrum/utils'; // TODO: what style overrides should be allowed? -export interface FullscreenDialogProps extends Omit, StyleProps { +export interface FullscreenDialogProps extends Omit, StyleProps { /** * The variant of fullscreen dialog to display. * @default "fullscreen" diff --git a/packages/@react-spectrum/s2/src/Link.tsx b/packages/@react-spectrum/s2/src/Link.tsx index f3f73977ada..cffb2783dbb 100644 --- a/packages/@react-spectrum/s2/src/Link.tsx +++ b/packages/@react-spectrum/s2/src/Link.tsx @@ -34,7 +34,7 @@ interface LinkStyleProps { isQuiet?: boolean } -export interface LinkProps extends Omit, StyleProps, LinkStyleProps { +export interface LinkProps extends Omit, StyleProps, LinkStyleProps { children: ReactNode } diff --git a/packages/@react-spectrum/s2/src/Menu.tsx b/packages/@react-spectrum/s2/src/Menu.tsx index ec0b76cbd18..d442bece48b 100644 --- a/packages/@react-spectrum/s2/src/Menu.tsx +++ b/packages/@react-spectrum/s2/src/Menu.tsx @@ -74,7 +74,7 @@ export interface MenuTriggerProps extends Omit extends Omit, 'children' | 'style' | 'className' | 'dependencies' | 'renderEmptyState' | keyof GlobalDOMAttributes>, StyleProps { +export interface MenuProps extends Omit, 'children' | 'style' | 'className' | 'render' | 'dependencies' | 'renderEmptyState' | keyof GlobalDOMAttributes>, StyleProps { /** * The size of the Menu. * @@ -421,7 +421,7 @@ export function Divider(props: SeparatorProps): ReactNode { ); } -export interface MenuSectionProps extends Omit, 'style' | 'className' | keyof GlobalDOMAttributes> {} +export interface MenuSectionProps extends Omit, 'style' | 'className' | 'render' | keyof GlobalDOMAttributes> {} export function MenuSection(props: MenuSectionProps): ReactNode { // remember, context doesn't work if it's around Section nor inside @@ -438,7 +438,7 @@ export function MenuSection(props: MenuSectionProps): React ); } -export interface MenuItemProps extends Omit, StyleProps { +export interface MenuItemProps extends Omit, StyleProps { /** * The contents of the item. */ diff --git a/packages/@react-spectrum/s2/src/Meter.tsx b/packages/@react-spectrum/s2/src/Meter.tsx index 0c95b7e5b64..ef72ae7339f 100644 --- a/packages/@react-spectrum/s2/src/Meter.tsx +++ b/packages/@react-spectrum/s2/src/Meter.tsx @@ -48,7 +48,7 @@ interface MeterStyleProps { labelPosition?: LabelPosition } -export interface MeterProps extends Omit, MeterStyleProps, StyleProps { +export interface MeterProps extends Omit, MeterStyleProps, StyleProps { /** The content to display as the label. */ label?: ReactNode } diff --git a/packages/@react-spectrum/s2/src/Modal.tsx b/packages/@react-spectrum/s2/src/Modal.tsx index ad55a2b3b24..a7927be2941 100644 --- a/packages/@react-spectrum/s2/src/Modal.tsx +++ b/packages/@react-spectrum/s2/src/Modal.tsx @@ -18,7 +18,7 @@ import {ModalOverlay, ModalOverlayProps, Modal as RACModal, useLocale} from 'rea import {style} from '../style' with {type: 'macro'}; import {useDOMRef} from '@react-spectrum/utils'; -interface ModalProps extends Omit { +interface ModalProps extends Omit { /** * The size of the Modal. * diff --git a/packages/@react-spectrum/s2/src/NumberField.tsx b/packages/@react-spectrum/s2/src/NumberField.tsx index 8a9a189d2a3..d5201bd01c8 100644 --- a/packages/@react-spectrum/s2/src/NumberField.tsx +++ b/packages/@react-spectrum/s2/src/NumberField.tsx @@ -38,7 +38,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps'; export interface NumberFieldProps extends - Omit, + Omit, StyleProps, SpectrumLabelableProps, HelpTextProps, diff --git a/packages/@react-spectrum/s2/src/Picker.tsx b/packages/@react-spectrum/s2/src/Picker.tsx index 4db143d221d..766d4be7882 100644 --- a/packages/@react-spectrum/s2/src/Picker.tsx +++ b/packages/@react-spectrum/s2/src/Picker.tsx @@ -98,7 +98,7 @@ export interface PickerStyleProps { type SelectionMode = 'single' | 'multiple'; export interface PickerProps extends - Omit, 'children' | 'style' | 'className' | 'allowsEmptyCollection' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>, + Omit, 'children' | 'style' | 'className' | 'render' | 'allowsEmptyCollection' | 'isTriggerUpWhenOpen' | keyof GlobalDOMAttributes>, PickerStyleProps, StyleProps, SpectrumLabelableProps, @@ -602,7 +602,7 @@ const PickerButton = createHideableComponent(function PickerButton, StyleProps { +export interface PickerItemProps extends Omit, StyleProps { children: ReactNode } @@ -673,7 +673,7 @@ function DefaultProvider({context, value, children}: {context: React.Context{children}; } -export interface PickerSectionProps extends Omit, 'style' | 'className' | keyof GlobalDOMAttributes>, StyleProps {} +export interface PickerSectionProps extends Omit, 'style' | 'className' | 'render' | keyof GlobalDOMAttributes>, StyleProps {} export function PickerSection(props: PickerSectionProps): ReactNode { let {size} = useContext(InternalPickerContext); return ( diff --git a/packages/@react-spectrum/s2/src/Popover.tsx b/packages/@react-spectrum/s2/src/Popover.tsx index e18bc565322..407598963ee 100644 --- a/packages/@react-spectrum/s2/src/Popover.tsx +++ b/packages/@react-spectrum/s2/src/Popover.tsx @@ -40,6 +40,7 @@ export interface PopoverProps extends UnsafeStyles, Omit { /** @@ -255,7 +256,7 @@ export interface PopoverDialogProps extends Pick, Omit, UnsafeStyles { +>, Omit, UnsafeStyles { /** * The children of the popover. */ diff --git a/packages/@react-spectrum/s2/src/ProgressBar.tsx b/packages/@react-spectrum/s2/src/ProgressBar.tsx index 71e98fdb3f8..b8904fc0aea 100644 --- a/packages/@react-spectrum/s2/src/ProgressBar.tsx +++ b/packages/@react-spectrum/s2/src/ProgressBar.tsx @@ -50,7 +50,7 @@ interface ProgressBarStyleProps { } -export interface ProgressBarProps extends Omit, ProgressBarStyleProps, StyleProps { +export interface ProgressBarProps extends Omit, ProgressBarStyleProps, StyleProps { /** The content to display as the label. */ label?: ReactNode } diff --git a/packages/@react-spectrum/s2/src/ProgressCircle.tsx b/packages/@react-spectrum/s2/src/ProgressCircle.tsx index 90ed77b60a2..b50a812be02 100644 --- a/packages/@react-spectrum/s2/src/ProgressCircle.tsx +++ b/packages/@react-spectrum/s2/src/ProgressCircle.tsx @@ -104,7 +104,7 @@ const hcmStroke = style({ } }); -export interface ProgressCircleProps extends Omit, ProgressCircleStyleProps, UnsafeStyles { +export interface ProgressCircleProps extends Omit, ProgressCircleStyleProps, UnsafeStyles { /** Spectrum-defined styles, returned by the `style()` macro. */ styles?: StylesPropWithHeight } diff --git a/packages/@react-spectrum/s2/src/Radio.tsx b/packages/@react-spectrum/s2/src/Radio.tsx index ea4c535d9c1..8ca32b3ce3a 100644 --- a/packages/@react-spectrum/s2/src/Radio.tsx +++ b/packages/@react-spectrum/s2/src/Radio.tsx @@ -24,7 +24,7 @@ import {forwardRef, ReactNode, useContext, useRef} from 'react'; import {pressScale} from './pressScale'; import {useFocusableRef} from '@react-spectrum/utils'; -export interface RadioProps extends Omit, StyleProps { +export interface RadioProps extends Omit, StyleProps { /** * The label for the element. */ diff --git a/packages/@react-spectrum/s2/src/RadioGroup.tsx b/packages/@react-spectrum/s2/src/RadioGroup.tsx index 2d979c3a350..154138571ee 100644 --- a/packages/@react-spectrum/s2/src/RadioGroup.tsx +++ b/packages/@react-spectrum/s2/src/RadioGroup.tsx @@ -24,7 +24,7 @@ import {style} from '../style' with {type: 'macro'}; import {useDOMRef} from '@react-spectrum/utils'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface RadioGroupProps extends Omit, StyleProps, SpectrumLabelableProps, HelpTextProps { +export interface RadioGroupProps extends Omit, StyleProps, SpectrumLabelableProps, HelpTextProps { /** * The Radios contained within the RadioGroup. */ diff --git a/packages/@react-spectrum/s2/src/RangeCalendar.tsx b/packages/@react-spectrum/s2/src/RangeCalendar.tsx index 7a11511df81..fc0ae4b1a98 100644 --- a/packages/@react-spectrum/s2/src/RangeCalendar.tsx +++ b/packages/@react-spectrum/s2/src/RangeCalendar.tsx @@ -34,7 +34,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps'; export interface RangeCalendarProps - extends Omit, 'visibleDuration' | 'style' | 'className' | 'children' | 'styles' | keyof GlobalDOMAttributes>, + extends Omit, 'visibleDuration' | 'style' | 'className' | 'render' | 'children' | 'styles' | keyof GlobalDOMAttributes>, StyleProps { /** * The error message to display when the calendar is invalid. diff --git a/packages/@react-spectrum/s2/src/SearchField.tsx b/packages/@react-spectrum/s2/src/SearchField.tsx index 0d6965299db..a5f8d00120d 100644 --- a/packages/@react-spectrum/s2/src/SearchField.tsx +++ b/packages/@react-spectrum/s2/src/SearchField.tsx @@ -32,7 +32,7 @@ import SearchIcon from '../s2wf-icons/S2_Icon_Search_20_N.svg'; import {TextFieldRef} from '@react-types/textfield'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface SearchFieldProps extends Omit, StyleProps, SpectrumLabelableProps, HelpTextProps, Pick { +export interface SearchFieldProps extends Omit, StyleProps, SpectrumLabelableProps, HelpTextProps, Pick { /** * The size of the SearchField. * diff --git a/packages/@react-spectrum/s2/src/SelectBoxGroup.tsx b/packages/@react-spectrum/s2/src/SelectBoxGroup.tsx index 19e421078da..3b6f40b20d4 100644 --- a/packages/@react-spectrum/s2/src/SelectBoxGroup.tsx +++ b/packages/@react-spectrum/s2/src/SelectBoxGroup.tsx @@ -30,7 +30,7 @@ import {TextContext} from './Content'; import {useFocusVisible} from 'react-aria'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface SelectBoxGroupProps extends StyleProps, Omit, keyof GlobalDOMAttributes | 'layout' | 'dragAndDropHooks' | 'dependencies' | 'renderEmptyState' | 'children' | 'onAction' | 'shouldFocusOnHover' | 'selectionBehavior' | 'shouldSelectOnPressUp' | 'shouldFocusWrap' | 'style' | 'className'> { +export interface SelectBoxGroupProps extends StyleProps, Omit, keyof GlobalDOMAttributes | 'layout' | 'dragAndDropHooks' | 'dependencies' | 'renderEmptyState' | 'children' | 'onAction' | 'shouldFocusOnHover' | 'selectionBehavior' | 'shouldSelectOnPressUp' | 'shouldFocusWrap' | 'style' | 'className' | 'render'> { /** * The SelectBox elements contained within the SelectBoxGroup. */ diff --git a/packages/@react-spectrum/s2/src/Slider.tsx b/packages/@react-spectrum/s2/src/Slider.tsx index 8b8c140e759..ed7d2e446f1 100644 --- a/packages/@react-spectrum/s2/src/Slider.tsx +++ b/packages/@react-spectrum/s2/src/Slider.tsx @@ -32,7 +32,7 @@ import {useFocusableRef} from '@react-spectrum/utils'; import {useLocale, useNumberFormatter} from '@react-aria/i18n'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface SliderBaseProps extends Omit, 'children' | 'style' | 'className' | 'orientation' | keyof GlobalDOMAttributes>, Omit, StyleProps { +export interface SliderBaseProps extends Omit, 'children' | 'style' | 'className' | 'render' | 'orientation' | keyof GlobalDOMAttributes>, Omit, StyleProps { children?: ReactNode, /** * The size of the Slider. diff --git a/packages/@react-spectrum/s2/src/Switch.tsx b/packages/@react-spectrum/s2/src/Switch.tsx index f194a23533d..61ad2dfa085 100644 --- a/packages/@react-spectrum/s2/src/Switch.tsx +++ b/packages/@react-spectrum/s2/src/Switch.tsx @@ -42,7 +42,7 @@ interface SwitchStyleProps { interface RenderProps extends SwitchRenderProps, SwitchStyleProps {} -export interface SwitchProps extends Omit, StyleProps, SwitchStyleProps { +export interface SwitchProps extends Omit, StyleProps, SwitchStyleProps { children?: ReactNode } diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index 539b564e3f3..b5e66fd84a2 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -120,7 +120,7 @@ interface S2TableProps { } // TODO: Note that loadMore and loadingState are now on the Table instead of on the TableBody -export interface TableViewProps extends Omit, DOMProps, UnsafeStyles, S2TableProps { +export interface TableViewProps extends Omit, DOMProps, UnsafeStyles, S2TableProps { /** Spectrum-defined styles, returned by the `style()` macro. */ styles?: StylesPropWithHeight } @@ -388,7 +388,7 @@ const centeredWrapper = style({ height: 'full' }); -export interface TableBodyProps extends Omit, 'style' | 'className' | keyof GlobalDOMAttributes> {} +export interface TableBodyProps extends Omit, 'style' | 'className' | 'render' | keyof GlobalDOMAttributes> {} /** * The body of a ``, containing the table rows. @@ -522,7 +522,7 @@ const columnStyles = style({ forcedColorAdjust: 'none' }); -export interface ColumnProps extends Omit { +export interface ColumnProps extends Omit { /** Whether the column should render a divider between it and the next column. */ showDivider?: boolean, /** Whether the column allows resizing. */ @@ -885,7 +885,7 @@ const selectAllCheckboxColumn = style({ backgroundColor: 'gray-75' }); -export interface TableHeaderProps extends Omit, 'style' | 'className' | 'onHoverChange' | 'onHoverStart' | 'onHoverEnd' | keyof GlobalDOMAttributes> {} +export interface TableHeaderProps extends Omit, 'style' | 'className' | 'render' | 'onHoverChange' | 'onHoverStart' | 'onHoverEnd' | keyof GlobalDOMAttributes> {} /** * A header within a `
`, containing the table columns. @@ -1030,7 +1030,7 @@ const cellContent = style({ } }); -export interface CellProps extends Omit, Pick { +export interface CellProps extends Omit, Pick { /** @private */ isSticky?: boolean, /** The content to render as the cell children. */ diff --git a/packages/@react-spectrum/s2/src/Tabs.tsx b/packages/@react-spectrum/s2/src/Tabs.tsx index b69c13b05f8..50cf49b571d 100644 --- a/packages/@react-spectrum/s2/src/Tabs.tsx +++ b/packages/@react-spectrum/s2/src/Tabs.tsx @@ -42,7 +42,7 @@ import {useHasTabbableChild} from '@react-aria/focus'; import {useLocale} from '@react-aria/i18n'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface TabsProps extends Omit, UnsafeStyles { +export interface TabsProps extends Omit, UnsafeStyles { /** Spectrum-defined styles, returned by the `style()` macro. */ styles?: StylesPropWithHeight, /** The content to display in the tabs. */ @@ -60,17 +60,17 @@ export interface TabsProps extends Omit, StyleProps { +export interface TabProps extends Omit, StyleProps { /** The content to display in the tab. */ children: ReactNode } -export interface TabListProps extends Omit, 'style' | 'className' | 'aria-label' | 'aria-labelledby' | keyof GlobalDOMAttributes>, StyleProps { +export interface TabListProps extends Omit, 'style' | 'className' | 'render' | 'aria-label' | 'aria-labelledby' | keyof GlobalDOMAttributes>, StyleProps { /** The content to display in the tablist. */ children: ReactNode | ((item: T) => ReactNode) } -export interface TabPanelProps extends Omit, UnsafeStyles { +export interface TabPanelProps extends Omit, UnsafeStyles { /** Spectrum-defined styles, returned by the `style()` macro. */ styles?: StylesPropWithHeight, /** The content to display in the tab panels. */ diff --git a/packages/@react-spectrum/s2/src/TabsPicker.tsx b/packages/@react-spectrum/s2/src/TabsPicker.tsx index 418cf01ea34..b7ccea11504 100644 --- a/packages/@react-spectrum/s2/src/TabsPicker.tsx +++ b/packages/@react-spectrum/s2/src/TabsPicker.tsx @@ -58,7 +58,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps'; export interface PickerStyleProps { } export interface PickerProps extends - Omit, 'children' | 'style' | 'className' | 'placeholder' | 'isTriggerUpWhenOpen'>, + Omit, 'children' | 'style' | 'className' | 'render' | 'placeholder' | 'isTriggerUpWhenOpen'>, PickerStyleProps, StyleProps, SpectrumLabelableProps, @@ -335,7 +335,7 @@ function TabLine(props: {isDisabled?: boolean}) { } -export interface PickerItemProps extends Omit, StyleProps { +export interface PickerItemProps extends Omit, StyleProps { children: ReactNode } export function PickerItem(props: PickerItemProps): ReactNode { diff --git a/packages/@react-spectrum/s2/src/TagGroup.tsx b/packages/@react-spectrum/s2/src/TagGroup.tsx index 7b039822c43..1ee4a4e6d0e 100644 --- a/packages/@react-spectrum/s2/src/TagGroup.tsx +++ b/packages/@react-spectrum/s2/src/TagGroup.tsx @@ -52,12 +52,12 @@ import {useLocalizedStringFormatter} from '@react-aria/i18n'; import {useSpectrumContextProps} from './useSpectrumContextProps'; // Get types from RSP and extend those? -export interface TagProps extends Omit, LabelableProps { +export interface TagProps extends Omit, LabelableProps { /** The children of the tag. */ children: ReactNode } -export interface TagGroupProps extends Omit, Pick, 'items' | 'children' | 'renderEmptyState'>, Omit, StyleProps, Omit { +export interface TagGroupProps extends Omit, Pick, 'items' | 'children' | 'renderEmptyState'>, Omit, StyleProps, Omit { /** A description for the tag group. */ description?: ReactNode, /** diff --git a/packages/@react-spectrum/s2/src/TextField.tsx b/packages/@react-spectrum/s2/src/TextField.tsx index b82705b2ae2..c6bb561aa2d 100644 --- a/packages/@react-spectrum/s2/src/TextField.tsx +++ b/packages/@react-spectrum/s2/src/TextField.tsx @@ -33,7 +33,7 @@ import {StyleString} from '../style/types'; import {TextFieldRef} from '@react-types/textfield'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface TextFieldProps extends Omit, StyleProps, SpectrumLabelableProps, HelpTextProps, Pick { +export interface TextFieldProps extends Omit, StyleProps, SpectrumLabelableProps, HelpTextProps, Pick { /** * The size of the text field. * diff --git a/packages/@react-spectrum/s2/src/TimeField.tsx b/packages/@react-spectrum/s2/src/TimeField.tsx index 6af9b2d9d4b..2909dfce5df 100644 --- a/packages/@react-spectrum/s2/src/TimeField.tsx +++ b/packages/@react-spectrum/s2/src/TimeField.tsx @@ -27,7 +27,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps'; export interface TimeFieldProps extends - Omit, 'children' | 'className' | 'style' | keyof GlobalDOMAttributes>, + Omit, 'children' | 'className' | 'style' | 'render' | keyof GlobalDOMAttributes>, StyleProps, SpectrumLabelableProps, HelpTextProps { diff --git a/packages/@react-spectrum/s2/src/Toast.tsx b/packages/@react-spectrum/s2/src/Toast.tsx index ad54fe3dc63..572eb2389ea 100644 --- a/packages/@react-spectrum/s2/src/Toast.tsx +++ b/packages/@react-spectrum/s2/src/Toast.tsx @@ -34,7 +34,7 @@ import {useMediaQuery} from '@react-spectrum/utils'; import {useOverlayTriggerState} from 'react-stately'; export type ToastPlacement = 'top' | 'top end' | 'bottom' | 'bottom end'; -export interface ToastContainerProps extends Omit, 'queue' | 'children' | 'style' | 'className'> { +export interface ToastContainerProps extends Omit, 'queue' | 'children' | 'style' | 'className' | 'render'> { /** * Placement of the toast container on the page. * @default "bottom" diff --git a/packages/@react-spectrum/s2/src/ToggleButton.tsx b/packages/@react-spectrum/s2/src/ToggleButton.tsx index c681aabc3d7..4aa9d0c79a2 100644 --- a/packages/@react-spectrum/s2/src/ToggleButton.tsx +++ b/packages/@react-spectrum/s2/src/ToggleButton.tsx @@ -26,7 +26,7 @@ import {useFocusableRef} from '@react-spectrum/utils'; import {useFormProps} from './Form'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface ToggleButtonProps extends Omit, StyleProps, ActionButtonStyleProps { +export interface ToggleButtonProps extends Omit, StyleProps, ActionButtonStyleProps { /** The content to display in the button. */ children: ReactNode, /** Whether the button should be displayed with an [emphasized style](https://spectrum.adobe.com/page/action-button/#Emphasis). */ diff --git a/packages/@react-spectrum/s2/src/ToggleButtonGroup.tsx b/packages/@react-spectrum/s2/src/ToggleButtonGroup.tsx index 022f0bc0119..a45ebd3fc60 100644 --- a/packages/@react-spectrum/s2/src/ToggleButtonGroup.tsx +++ b/packages/@react-spectrum/s2/src/ToggleButtonGroup.tsx @@ -16,7 +16,7 @@ import {createContext, ForwardedRef, forwardRef} from 'react'; import {DOMProps, GlobalDOMAttributes} from '@react-types/shared'; import {useSpectrumContextProps} from './useSpectrumContextProps'; -export interface ToggleButtonGroupProps extends ActionButtonGroupProps, Omit, DOMProps { +export interface ToggleButtonGroupProps extends ActionButtonGroupProps, Omit, DOMProps { /** Whether the button should be displayed with an [emphasized style](https://spectrum.adobe.com/page/action-button/#Emphasis). */ isEmphasized?: boolean } diff --git a/packages/@react-spectrum/s2/src/Tooltip.tsx b/packages/@react-spectrum/s2/src/Tooltip.tsx index 504cba97f73..f3d56380539 100644 --- a/packages/@react-spectrum/s2/src/Tooltip.tsx +++ b/packages/@react-spectrum/s2/src/Tooltip.tsx @@ -38,7 +38,7 @@ export interface TooltipTriggerProps extends Omit, DOMProps, UnsafeStyles { +export interface TooltipProps extends Omit, DOMProps, UnsafeStyles { /** The content of the tooltip. */ children: ReactNode } diff --git a/packages/@react-spectrum/s2/src/TreeView.tsx b/packages/@react-spectrum/s2/src/TreeView.tsx index b1e28c32f27..f0a167192c0 100644 --- a/packages/@react-spectrum/s2/src/TreeView.tsx +++ b/packages/@react-spectrum/s2/src/TreeView.tsx @@ -50,12 +50,12 @@ interface S2TreeProps { onAction?: (key: Key) => void } -export interface TreeViewProps extends Omit, 'style' | 'className' | 'onRowAction' | 'selectionBehavior' | 'onScroll' | 'onCellAction' | 'dragAndDropHooks' | keyof GlobalDOMAttributes>, UnsafeStyles, S2TreeProps { +export interface TreeViewProps extends Omit, 'style' | 'className' | 'render' | 'onRowAction' | 'selectionBehavior' | 'onScroll' | 'onCellAction' | 'dragAndDropHooks' | keyof GlobalDOMAttributes>, UnsafeStyles, S2TreeProps { /** Spectrum-defined styles, returned by the `style()` macro. */ styles?: StylesPropWithHeight } -export interface TreeViewItemProps extends Omit { +export interface TreeViewItemProps extends Omit { /** Whether this item has children, even if not loaded yet. */ hasChildItems?: boolean } diff --git a/packages/@react-spectrum/tree/src/TreeView.tsx b/packages/@react-spectrum/tree/src/TreeView.tsx index 722f7af2d5b..0ca1725ae9a 100644 --- a/packages/@react-spectrum/tree/src/TreeView.tsx +++ b/packages/@react-spectrum/tree/src/TreeView.tsx @@ -34,7 +34,7 @@ import {SlotProvider, useDOMRef, useStyleProps} from '@react-spectrum/utils'; import {useButton} from '@react-aria/button'; import {useLocale} from '@react-aria/i18n'; -export interface SpectrumTreeViewProps extends Omit, 'children'>, StyleProps, SpectrumSelectionProps, Expandable { +export interface SpectrumTreeViewProps extends Omit, 'children' | 'render'>, StyleProps, SpectrumSelectionProps, Expandable { /** Provides content to display when there are no items in the tree. */ renderEmptyState?: () => JSX.Element, /** @@ -48,7 +48,7 @@ export interface SpectrumTreeViewProps extends Omit, 'childr children?: ReactNode | ((item: T) => ReactNode) } -export interface SpectrumTreeViewItemProps extends Omit { +export interface SpectrumTreeViewItemProps extends Omit { /** Rendered contents of the tree item or child items. */ children: ReactNode } diff --git a/packages/dev/s2-docs/src/ComponentCardView.tsx b/packages/dev/s2-docs/src/ComponentCardView.tsx index 184f8097a6d..164530d5a55 100644 --- a/packages/dev/s2-docs/src/ComponentCardView.tsx +++ b/packages/dev/s2-docs/src/ComponentCardView.tsx @@ -25,7 +25,7 @@ interface ComponentCardGridProps { export function ComponentCardView({items, ariaLabel = 'Items', size = 'S', currentUrl, onAction, renderEmptyState}: ComponentCardGridProps) { return ( - + { +export interface TabsProps extends Omit { /** The content to display in the tabs. */ children: ReactNode } -export interface TabProps extends Omit { +export interface TabProps extends Omit { /** The content to display in the tab. */ children: ReactNode } -export interface TabListProps extends Omit, 'style' | 'className' | 'aria-label' | 'aria-labelledby'> { +export interface TabListProps extends Omit, 'style' | 'className' | 'render' | 'aria-label' | 'aria-labelledby'> { /** The content to display in the tablist. */ children: ReactNode | ((item: T) => ReactNode) } -export interface TabPanelProps extends Omit { +export interface TabPanelProps extends Omit { /** The content to display in the tab panels. */ children: ReactNode } diff --git a/packages/react-aria-components/src/Breadcrumbs.tsx b/packages/react-aria-components/src/Breadcrumbs.tsx index 9149c9c1ab7..de2ae2a0883 100644 --- a/packages/react-aria-components/src/Breadcrumbs.tsx +++ b/packages/react-aria-components/src/Breadcrumbs.tsx @@ -14,6 +14,8 @@ import {AriaLabelingProps, forwardRefType, GlobalDOMAttributes, Key} from '@reac import { ClassNameOrFunction, ContextValue, + dom, + DOMRenderProps, RenderProps, SlotProps, StyleProps, @@ -28,7 +30,7 @@ import {LinkContext} from './Link'; import {Node} from 'react-stately'; import React, {createContext, ForwardedRef, forwardRef, useContext} from 'react'; -export interface BreadcrumbsProps extends Omit, 'disabledKeys'>, AriaBreadcrumbsProps, StyleProps, SlotProps, AriaLabelingProps, GlobalDOMAttributes { +export interface BreadcrumbsProps extends Omit, 'disabledKeys'>, AriaBreadcrumbsProps, StyleProps, SlotProps, AriaLabelingProps, DOMRenderProps<'ol', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-Breadcrumbs' @@ -54,7 +56,8 @@ export const Breadcrumbs = /*#__PURE__*/ (forwardRef as forwardRefType)(function return ( }> {collection => ( -
    -
+ )}
); @@ -82,7 +85,7 @@ export interface BreadcrumbRenderProps { isDisabled: boolean } -export interface BreadcrumbProps extends RenderProps, AriaLabelingProps, GlobalDOMAttributes { +export interface BreadcrumbProps extends RenderProps, AriaLabelingProps, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Breadcrumb' @@ -120,7 +123,7 @@ export const Breadcrumb = /*#__PURE__*/ createLeafComponent(BreadcrumbNode, func delete DOMProps.id; return ( -
  • {renderProps.children} -
  • + ); }); diff --git a/packages/react-aria-components/src/Button.tsx b/packages/react-aria-components/src/Button.tsx index ffbba12ab59..d43d789db59 100644 --- a/packages/react-aria-components/src/Button.tsx +++ b/packages/react-aria-components/src/Button.tsx @@ -23,6 +23,7 @@ import { import { ClassNameOrFunction, ContextValue, + dom, RenderProps, SlotProps, useContextProps, @@ -67,7 +68,7 @@ export interface ButtonRenderProps { isPending: boolean } -export interface ButtonProps extends Omit, HoverEvents, SlotProps, RenderProps, Omit, 'onClick'> { +export interface ButtonProps extends Omit, HoverEvents, SlotProps, RenderProps, Omit, 'onClick'> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Button' @@ -144,7 +145,7 @@ export const Button = /*#__PURE__*/ createHideableComponent(function Button(prop delete DOMProps.onClick; return ( - + ); }); diff --git a/packages/react-aria-components/src/Calendar.tsx b/packages/react-aria-components/src/Calendar.tsx index de17a651abb..ea895b2c97c 100644 --- a/packages/react-aria-components/src/Calendar.tsx +++ b/packages/react-aria-components/src/Calendar.tsx @@ -29,7 +29,9 @@ import {CalendarState, RangeCalendarState, useCalendarState, useRangeCalendarSta import { ClassNameOrFunction, ContextValue, + dom, DOMProps, + DOMRenderProps, Provider, RenderProps, SlotProps, @@ -68,7 +70,7 @@ export interface RangeCalendarRenderProps extends Omit extends Omit, 'errorMessage' | 'validationState'>, RenderProps, SlotProps, GlobalDOMAttributes { +export interface CalendarProps extends Omit, 'errorMessage' | 'validationState'>, RenderProps, SlotProps, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Calendar' @@ -87,7 +89,7 @@ export interface CalendarProps extends Omit ICalendar } -export interface RangeCalendarProps extends Omit, 'errorMessage' | 'validationState'>, RenderProps, SlotProps, GlobalDOMAttributes { +export interface RangeCalendarProps extends Omit, 'errorMessage' | 'validationState'>, RenderProps, SlotProps, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-RangeCalendar' @@ -138,7 +140,7 @@ export const Calendar = /*#__PURE__*/ (forwardRef as forwardRefType)(function Ca let DOMProps = filterDOMProps(props, {global: true}); return ( -
    -
    + ); }); @@ -216,7 +218,7 @@ export const RangeCalendar = /*#__PURE__*/ (forwardRef as forwardRefType)(functi let DOMProps = filterDOMProps(props, {global: true}); return ( -
    -
    + ); }); @@ -344,7 +346,7 @@ export interface CalendarCellRenderProps { isToday: boolean } -export interface CalendarGridProps extends StyleProps, GlobalDOMAttributes { +export interface CalendarGridProps extends StyleProps, DOMRenderProps<'table', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-CalendarGrid' @@ -407,7 +409,8 @@ export const CalendarGrid = /*#__PURE__*/ (forwardRef as forwardRefType)(functio return ( -
    ) } -
    + ); }); -export interface CalendarGridHeaderProps extends StyleProps, GlobalDOMAttributes { +export interface CalendarGridHeaderProps extends StyleProps, DOMRenderProps<'thead', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-CalendarGridHeader' @@ -445,7 +448,8 @@ function CalendarGridHeader(props: CalendarGridHeaderProps, ref: ForwardedRef {weekDays.map((day, key) => React.cloneElement(children(day), {key}))} - + ); } @@ -463,7 +467,7 @@ function CalendarGridHeader(props: CalendarGridHeaderProps, ref: ForwardedRef { +export interface CalendarHeaderCellProps extends DOMProps, DOMRenderProps<'th', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-CalendarHeaderCell' @@ -475,13 +479,14 @@ function CalendarHeaderCell(props: CalendarHeaderCellProps, ref: ForwardedRef {children} - + ); } @@ -491,7 +496,7 @@ function CalendarHeaderCell(props: CalendarHeaderCellProps, ref: ForwardedRef { +export interface CalendarGridBodyProps extends StyleProps, DOMRenderProps<'tbody', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-CalendarGridBody' @@ -510,7 +515,8 @@ function CalendarGridBody(props: CalendarGridBodyProps, ref: ForwardedRef ))} - + ); } @@ -534,7 +540,7 @@ function CalendarGridBody(props: CalendarGridBodyProps, ref: ForwardedRef, HoverEvents, GlobalDOMAttributes { +export interface CalendarCellProps extends RenderProps, HoverEvents, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-CalendarCell' @@ -608,7 +614,7 @@ export const CalendarCell = /*#__PURE__*/ (forwardRef as forwardRefType)(functio return ( -
    + ); }); diff --git a/packages/react-aria-components/src/Checkbox.tsx b/packages/react-aria-components/src/Checkbox.tsx index c32c6428e1d..7050f5b089b 100644 --- a/packages/react-aria-components/src/Checkbox.tsx +++ b/packages/react-aria-components/src/Checkbox.tsx @@ -15,6 +15,7 @@ import {CheckboxGroupState, useCheckboxGroupState, useToggleState} from 'react-s import { ClassNameOrFunction, ContextValue, + dom, Provider, RACValidation, removeDataAttributes, @@ -33,14 +34,14 @@ import {LabelContext} from './Label'; import React, {createContext, ForwardedRef, forwardRef, useContext, useMemo} from 'react'; import {TextContext} from './Text'; -export interface CheckboxGroupProps extends Omit, RACValidation, RenderProps, SlotProps, GlobalDOMAttributes { +export interface CheckboxGroupProps extends Omit, RACValidation, RenderProps, SlotProps, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-CheckboxGroup' */ className?: ClassNameOrFunction } -export interface CheckboxProps extends Omit, HoverEvents, RACValidation, RenderProps, SlotProps, Omit, 'onClick'> { +export interface CheckboxProps extends Omit, HoverEvents, RACValidation, RenderProps, SlotProps, Omit, 'onClick'> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Checkbox' @@ -170,7 +171,7 @@ export const CheckboxGroup = /*#__PURE__*/ (forwardRef as forwardRefType)(functi let DOMProps = filterDOMProps(props, {global: true}); return ( -
    {renderProps.children} -
    +
    ); }); @@ -258,7 +259,7 @@ export const Checkbox = /*#__PURE__*/ (forwardRef as forwardRefType)(function Ch delete DOMProps.onClick; return ( - + ); }); diff --git a/packages/react-aria-components/src/ColorArea.tsx b/packages/react-aria-components/src/ColorArea.tsx index 4106818da5b..cd4a0aa68c1 100644 --- a/packages/react-aria-components/src/ColorArea.tsx +++ b/packages/react-aria-components/src/ColorArea.tsx @@ -1,6 +1,7 @@ import {AriaColorAreaProps, useColorArea} from 'react-aria'; import { ClassNameOrFunction, + dom, Provider, RenderProps, SlotProps, @@ -71,7 +72,7 @@ export const ColorArea = forwardRef(function ColorArea(props: ColorAreaProps, re delete DOMProps.id; return ( -
    {renderProps.children} -
    + ); }); diff --git a/packages/react-aria-components/src/ColorField.tsx b/packages/react-aria-components/src/ColorField.tsx index 98dd799e728..79651af30ff 100644 --- a/packages/react-aria-components/src/ColorField.tsx +++ b/packages/react-aria-components/src/ColorField.tsx @@ -13,6 +13,7 @@ import {AriaColorFieldProps, useColorChannelField, useColorField, useLocale} from 'react-aria'; import { ClassNameOrFunction, + dom, Provider, RACValidation, removeDataAttributes, @@ -227,7 +228,7 @@ function useChildren( }], [FieldErrorContext, validation] ]}> -
    -
    diff --git a/packages/react-aria-components/src/ColorSwatchPicker.tsx b/packages/react-aria-components/src/ColorSwatchPicker.tsx index 7be59e946ea..c3460299e9e 100644 --- a/packages/react-aria-components/src/ColorSwatchPicker.tsx +++ b/packages/react-aria-components/src/ColorSwatchPicker.tsx @@ -108,6 +108,8 @@ export const ColorSwatchPickerItem = forwardRef(function ColorSwatchPickerItem(p return ( {yInputProps && } {renderProps.children} -
    + ); }); diff --git a/packages/react-aria-components/src/ColorWheel.tsx b/packages/react-aria-components/src/ColorWheel.tsx index 62975d56abf..8f3634c268e 100644 --- a/packages/react-aria-components/src/ColorWheel.tsx +++ b/packages/react-aria-components/src/ColorWheel.tsx @@ -2,6 +2,7 @@ import {AriaColorWheelOptions, useColorWheel} from 'react-aria'; import { ClassNameOrFunction, ContextValue, + dom, Provider, RenderProps, SlotProps, @@ -63,7 +64,7 @@ export const ColorWheel = forwardRef(function ColorWheel(props: ColorWheelProps, delete DOMProps.id; return ( -
    {renderProps.children} -
    + ); }); @@ -112,7 +113,7 @@ export const ColorWheelTrack = forwardRef(function ColorWheelTrack(props: ColorW }); return ( -
    ({props, collection, comboBoxRef: ref}: [GroupContext, {isInvalid: validation.isInvalid, isDisabled: props.isDisabled || false}], [FieldErrorContext, validation] ]}> -
    -
    -
    type: DateSegmentType } -export interface DateSegmentProps extends RenderProps, HoverEvents, GlobalDOMAttributes { +export interface DateSegmentProps extends RenderProps, HoverEvents, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-DateSegment' @@ -398,7 +399,7 @@ export const DateSegment = /*#__PURE__*/ (forwardRef as forwardRefType)(function }); return ( - -
    -
    void } -export interface DialogProps extends AriaDialogProps, StyleProps, SlotProps, GlobalDOMAttributes { +export interface DialogProps extends AriaDialogProps, StyleProps, SlotProps, DOMRenderProps<'section', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-Dialog' @@ -132,8 +132,9 @@ export const Dialog = /*#__PURE__*/ (forwardRef as forwardRefType)(function Dial let DOMProps = filterDOMProps(props, {global: true}); return ( -
    {renderProps.children} -
    + ); }); diff --git a/packages/react-aria-components/src/Disclosure.tsx b/packages/react-aria-components/src/Disclosure.tsx index 6bfebd7db32..a56b75d537a 100644 --- a/packages/react-aria-components/src/Disclosure.tsx +++ b/packages/react-aria-components/src/Disclosure.tsx @@ -16,6 +16,7 @@ import { ClassNameOrFunction, ContextValue, DEFAULT_SLOT, + dom, Provider, RenderProps, SlotProps, @@ -68,7 +69,7 @@ export const DisclosureGroup = forwardRef(function DisclosureGroup(props: Disclo let domProps = filterDOMProps(props, {global: true}); return ( -
    {renderProps.children} -
    + ); }); @@ -186,14 +187,14 @@ export const Disclosure = /*#__PURE__*/ (forwardRef as forwardRefType)(function [InternalDisclosureContext, {panelProps, panelRef}], [DisclosureStateContext, state] ]}> -
    {renderProps.children} -
    + ); }); @@ -242,7 +243,7 @@ export const DisclosurePanel = /*#__PURE__*/ (forwardRef as forwardRefType)(func }); let DOMProps = filterDOMProps(props, {global: true, labelable: true}); return ( -
    {props.children} -
    + ); }); diff --git a/packages/react-aria-components/src/DropZone.tsx b/packages/react-aria-components/src/DropZone.tsx index 298179b6ef9..d542fc1b641 100644 --- a/packages/react-aria-components/src/DropZone.tsx +++ b/packages/react-aria-components/src/DropZone.tsx @@ -14,6 +14,7 @@ import {AriaLabelingProps, GlobalDOMAttributes, HoverEvents} from '@react-types/ import { ClassNameOrFunction, ContextValue, + dom, Provider, RenderProps, SlotProps, @@ -110,8 +111,7 @@ export const DropZone = forwardRef(function DropZone(props: DropZoneProps, ref: values={[ [TextContext, {id: textId, slot: 'label'}] ]}> - {/* eslint-disable-next-line */} -
    {renderProps.children} -
    + ); }); diff --git a/packages/react-aria-components/src/Form.tsx b/packages/react-aria-components/src/Form.tsx index 09b8d8f7ef6..4b0061b5081 100644 --- a/packages/react-aria-components/src/Form.tsx +++ b/packages/react-aria-components/src/Form.tsx @@ -10,13 +10,13 @@ * governing permissions and limitations under the License. */ -import {ContextValue, DOMProps, useContextProps} from './utils'; +import {ContextValue, dom, DOMProps, DOMRenderProps, useContextProps} from './utils'; import {FormValidationContext} from 'react-stately'; import {GlobalDOMAttributes} from '@react-types/shared'; import React, {createContext, ForwardedRef, forwardRef} from 'react'; import {FormProps as SharedFormProps} from '@react-types/form'; -export interface FormProps extends SharedFormProps, DOMProps, GlobalDOMAttributes { +export interface FormProps extends SharedFormProps, DOMProps, DOMRenderProps<'form', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-Form' @@ -41,12 +41,12 @@ export const Form = forwardRef(function Form(props: FormProps, ref: ForwardedRef [props, ref] = useContextProps(props, ref, FormContext); let {validationErrors, validationBehavior = 'native', children, className, ...domProps} = props; return ( -
    + {children} - +
    ); }); diff --git a/packages/react-aria-components/src/GridList.tsx b/packages/react-aria-components/src/GridList.tsx index 7711cf95e4e..57aab3bab5a 100644 --- a/packages/react-aria-components/src/GridList.tsx +++ b/packages/react-aria-components/src/GridList.tsx @@ -16,6 +16,9 @@ import { ClassNameOrFunction, ContextValue, DEFAULT_SLOT, + dom, + DOMProps, + DOMRenderProps, Provider, RenderProps, SlotProps, @@ -230,8 +233,8 @@ function GridListInner({props, collection, gridListRef: ref}: state: filteredState }; let renderProps = useRenderProps({ - className: props.className, - style: props.style, + ...props, + children: undefined, defaultClassName: 'react-aria-GridList', values: renderValues }); @@ -254,7 +257,7 @@ function GridListInner({props, collection, gridListRef: ref}: return ( -
    } slot={props.slot || undefined} @@ -281,7 +284,7 @@ function GridListInner({props, collection, gridListRef: ref}: {emptyState} {dragPreview} -
    +
    ); } @@ -401,7 +404,7 @@ export const GridListItem = /*#__PURE__*/ createLeafComponent(ItemNode, function
    } -
    -
    + ); }); @@ -498,7 +501,7 @@ function GridListDropIndicator(props: GridListDropIndicatorProps, ref: Forwarded }); return ( -
    } @@ -507,7 +510,7 @@ function GridListDropIndicator(props: GridListDropIndicatorProps, ref: Forwarded
    {renderProps.children}
    -
    + ); } @@ -535,7 +538,7 @@ function RootDropIndicator() { ); } -export interface GridListLoadMoreItemProps extends Omit, StyleProps, GlobalDOMAttributes { +export interface GridListLoadMoreItemProps extends Omit, StyleProps, DOMRenderProps<'div', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-GridListLoadMoreItem' @@ -570,7 +573,7 @@ export const GridListLoadMoreItem = createLeafComponent(LoaderNode, function Gri id: undefined, children: item.rendered, defaultClassName: 'react-aria-GridListLoadingIndicator', - values: null + values: undefined }); // For now don't include aria-posinset and aria-setsize on loader since they aren't keyboard focusable // Arguably shouldn't include them ever since it might be confusing to the user to include the loaders as part of the @@ -584,7 +587,7 @@ export const GridListLoadMoreItem = createLeafComponent(LoaderNode, function Gri
    {isLoading && renderProps.children && ( -
    {renderProps.children}
    -
    + )} ); }); -export interface GridListSectionProps extends SectionProps { +export interface GridListSectionProps extends SectionProps, DOMRenderProps<'div', undefined> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-GridListSection' @@ -620,17 +623,18 @@ export const GridListSection = /*#__PURE__*/ createBranchComponent(SectionNode, 'aria-label': props['aria-label'] ?? undefined }, state, ref); let renderProps = useRenderProps({ + ...props, + id: undefined, + children: undefined, defaultClassName: 'react-aria-GridListSection', - className: props.className, - style: props.style, - values: {} + values: undefined }); let DOMProps = filterDOMProps(props as any, {global: true}); delete DOMProps.id; return ( -
    -
    + ); }); -export const GridListHeaderContext = createContext, HTMLDivElement>>({}); +export interface GridListHeaderProps extends DOMRenderProps<'div', undefined>, DOMProps, GlobalDOMAttributes {} + +export const GridListHeaderContext = createContext>({}); const GridListHeaderInnerContext = createContext | null>(null); -export const GridListHeader = /*#__PURE__*/ createLeafComponent(HeaderNode, function Header(props: HTMLAttributes, ref: ForwardedRef) { +export const GridListHeader = /*#__PURE__*/ createLeafComponent(HeaderNode, function Header(props: GridListHeaderProps, ref: ForwardedRef) { [props, ref] = useContextProps(props, ref, GridListHeaderContext); let rowHeaderProps = useContext(GridListHeaderInnerContext); return ( -
    +
    {props.children}
    -
    + ); }); diff --git a/packages/react-aria-components/src/Group.tsx b/packages/react-aria-components/src/Group.tsx index 7d84b88a8f1..5b7944601cf 100644 --- a/packages/react-aria-components/src/Group.tsx +++ b/packages/react-aria-components/src/Group.tsx @@ -12,12 +12,13 @@ import {AriaLabelingProps, DOMProps, forwardRefType} from '@react-types/shared'; import { - ClassNameOrFunction, - ContextValue, - RenderProps, - SlotProps, - useContextProps, - useRenderProps + ClassNameOrFunction, + ContextValue, + dom, + RenderProps, + SlotProps, + useContextProps, + useRenderProps } from './utils'; import {HoverProps, mergeProps, useFocusRing, useHover} from 'react-aria'; import React, {createContext, ForwardedRef, forwardRef, HTMLAttributes} from 'react'; @@ -50,7 +51,7 @@ export interface GroupRenderProps { isInvalid: boolean } -export interface GroupProps extends AriaLabelingProps, Omit, 'children' | 'className' | 'style' | 'role' | 'slot'>, DOMProps, HoverProps, RenderProps, SlotProps { +export interface GroupProps extends AriaLabelingProps, Omit, 'children' | 'className' | 'style' | 'render' | 'role' | 'slot'>, DOMProps, HoverProps, RenderProps, SlotProps { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Group' @@ -95,7 +96,7 @@ export const Group = /*#__PURE__*/ (forwardRef as forwardRefType)(function Group }); return ( -
    {renderProps.children} -
    + ); }); diff --git a/packages/react-aria-components/src/Header.tsx b/packages/react-aria-components/src/Header.tsx index a541100865b..7165dbe12fe 100644 --- a/packages/react-aria-components/src/Header.tsx +++ b/packages/react-aria-components/src/Header.tsx @@ -10,17 +10,19 @@ * governing permissions and limitations under the License. */ -import {ContextValue, useContextProps} from './utils'; +import {ContextValue, dom, DOMRenderProps, useContextProps} from './utils'; import {createLeafComponent, HeaderNode} from '@react-aria/collections'; import React, {createContext, ForwardedRef, HTMLAttributes} from 'react'; -export const HeaderContext = createContext, HTMLElement>>({}); +export interface HeaderProps extends HTMLAttributes, DOMRenderProps<'header', undefined> {} -export const Header = /*#__PURE__*/ createLeafComponent(HeaderNode, function Header(props: HTMLAttributes, ref: ForwardedRef) { +export const HeaderContext = createContext>({}); + +export const Header = /*#__PURE__*/ createLeafComponent(HeaderNode, function Header(props: HeaderProps, ref: ForwardedRef) { [props, ref] = useContextProps(props, ref, HeaderContext); return ( -
    + {props.children} -
    + ); }); diff --git a/packages/react-aria-components/src/Heading.tsx b/packages/react-aria-components/src/Heading.tsx index fc9649321df..2877a30d3fd 100644 --- a/packages/react-aria-components/src/Heading.tsx +++ b/packages/react-aria-components/src/Heading.tsx @@ -10,18 +10,18 @@ * governing permissions and limitations under the License. */ +import {dom, DOMRenderProps, useContextProps} from './utils'; import {HeadingContext} from './RSPContexts'; -import React, {ElementType, ForwardedRef, forwardRef, HTMLAttributes} from 'react'; -import {useContextProps} from './utils'; +import React, {ForwardedRef, forwardRef, HTMLAttributes} from 'react'; -export interface HeadingProps extends HTMLAttributes { +export interface HeadingProps extends HTMLAttributes, DOMRenderProps<'h1', undefined> { level?: number } export const Heading = forwardRef(function Heading(props: HeadingProps, ref: ForwardedRef) { [props, ref] = useContextProps(props, ref, HeadingContext); let {children, level = 3, className, ...domProps} = props; - let Element = `h${level}` as ElementType; + let Element = dom[`h${level}`]; return ( diff --git a/packages/react-aria-components/src/Input.tsx b/packages/react-aria-components/src/Input.tsx index 48f1bd6a41b..97cae53ad4c 100644 --- a/packages/react-aria-components/src/Input.tsx +++ b/packages/react-aria-components/src/Input.tsx @@ -13,6 +13,7 @@ import { ClassNameOrFunction, ContextValue, + dom, StyleRenderProps, useContextProps, useRenderProps @@ -49,7 +50,7 @@ export interface InputRenderProps { isInvalid: boolean } -export interface InputProps extends Omit, 'className' | 'style'>, HoverEvents, StyleRenderProps { +export interface InputProps extends Omit, 'className' | 'style'>, HoverEvents, StyleRenderProps { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Input' @@ -99,7 +100,7 @@ export const Input = /*#__PURE__*/ createHideableComponent(function Input(props: }); return ( - , DOMRenderProps<'kbd', undefined> {} + export const KeyboardContext = createContext, HTMLElement>>({}); export const Keyboard = forwardRef(function Keyboard(props: HTMLAttributes, ref: ForwardedRef) { [props, ref] = useContextProps(props, ref, KeyboardContext); - return ; + return ; }); diff --git a/packages/react-aria-components/src/Label.tsx b/packages/react-aria-components/src/Label.tsx index 961b792302a..70c22c63b2d 100644 --- a/packages/react-aria-components/src/Label.tsx +++ b/packages/react-aria-components/src/Label.tsx @@ -10,11 +10,11 @@ * governing permissions and limitations under the License. */ -import {ContextValue, useContextProps} from './utils'; +import {ContextValue, dom, DOMRenderProps, useContextProps} from './utils'; import {createHideableComponent} from '@react-aria/collections'; import React, {createContext, ForwardedRef, LabelHTMLAttributes} from 'react'; -export interface LabelProps extends LabelHTMLAttributes { +export interface LabelProps extends LabelHTMLAttributes, DOMRenderProps<'label', undefined> { elementType?: string } @@ -22,7 +22,8 @@ export const LabelContext = createContext) { [props, ref] = useContextProps(props, ref, LabelContext); - let {elementType: ElementType = 'label', ...labelProps} = props; + let {elementType = 'label', ...labelProps} = props; + let ElementType = dom[elementType]; // @ts-ignore return ; }); diff --git a/packages/react-aria-components/src/Link.tsx b/packages/react-aria-components/src/Link.tsx index 35f0667c727..74abcdac665 100644 --- a/packages/react-aria-components/src/Link.tsx +++ b/packages/react-aria-components/src/Link.tsx @@ -12,18 +12,20 @@ import {AriaLinkOptions, HoverEvents, mergeProps, useFocusRing, useHover, useLink} from 'react-aria'; import { - ClassNameOrFunction, - ContextValue, - RenderProps, - SlotProps, - useContextProps, - useRenderProps + ClassNameOrFunction, + ContextValue, + dom, + PossibleLinkDOMRenderProps, + RenderProps, + SlotProps, + useContextProps, + useRenderProps } from './utils'; import {DOMProps, forwardRefType, GlobalDOMAttributes} from '@react-types/shared'; import {filterDOMProps} from '@react-aria/utils'; -import React, {createContext, ElementType, ForwardedRef, forwardRef} from 'react'; +import React, {createContext, ForwardedRef, forwardRef} from 'react'; -export interface LinkProps extends Omit, HoverEvents, RenderProps, SlotProps, DOMProps, Omit, 'onClick'> { +export interface LinkProps extends Omit, HoverEvents, Omit, 'render'>, PossibleLinkDOMRenderProps<'span', LinkRenderProps>, SlotProps, DOMProps, Omit, 'onClick'> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Link' @@ -73,13 +75,14 @@ export const LinkContext = createContext) { [props, ref] = useContextProps(props, ref, LinkContext); - let ElementType: ElementType = props.href && !props.isDisabled ? 'a' : 'span'; - let {linkProps, isPressed} = useLink({...props, elementType: ElementType}, ref); + let elementType = props.href && !props.isDisabled ? 'a' : 'span'; + let {linkProps, isPressed} = useLink({...props, elementType}, ref); + let ElementType = dom[elementType]; let {hoverProps, isHovered} = useHover(props); let {focusProps, isFocused, isFocusVisible} = useFocusRing(); - let renderProps = useRenderProps({ + let renderProps = useRenderProps({ ...props, defaultClassName: 'react-aria-Link', values: { diff --git a/packages/react-aria-components/src/ListBox.tsx b/packages/react-aria-components/src/ListBox.tsx index 721db33ce6f..b149d8f54ee 100644 --- a/packages/react-aria-components/src/ListBox.tsx +++ b/packages/react-aria-components/src/ListBox.tsx @@ -15,6 +15,9 @@ import { ClassNameOrFunction, ContextValue, DEFAULT_SLOT, + dom, + DOMRenderProps, + PossibleLinkDOMRenderProps, Provider, RenderProps, SlotProps, @@ -231,8 +234,8 @@ function ListBoxInner({state: inputState, props, listBoxRef}: state }; let renderProps = useRenderProps({ - className: props.className, - style: props.style, + ...props, + children: undefined, defaultClassName: 'react-aria-ListBox', values: renderValues }); @@ -253,7 +256,7 @@ function ListBoxInner({state: inputState, props, listBoxRef}: return ( -
    } slot={props.slot || undefined} @@ -283,12 +286,12 @@ function ListBoxInner({state: inputState, props, listBoxRef}: {emptyState} {dragPreview} -
    +
    ); } -export interface ListBoxSectionProps extends SectionProps { +export interface ListBoxSectionProps extends SectionProps, DOMRenderProps<'section', undefined> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-ListBoxSection' @@ -306,17 +309,18 @@ function ListBoxSectionInner(props: ListBoxSectionProps, re 'aria-label': props['aria-label'] ?? undefined }); let renderProps = useRenderProps({ + ...props, + id: undefined, + children: undefined, defaultClassName: className, - className: props.className, - style: props.style, - values: {} + values: undefined }); let DOMProps = filterDOMProps(props as any, {global: true}); delete DOMProps.id; return ( -
    @@ -325,7 +329,7 @@ function ListBoxSectionInner(props: ListBoxSectionProps, re parent={section} renderDropIndicator={useRenderDropIndicator(dragAndDropHooks, dropState)} /> -
    + ); } @@ -336,7 +340,7 @@ export const ListBoxSection = /*#__PURE__*/ createBranchComponent(SectionNode, L export interface ListBoxItemRenderProps extends ItemRenderProps {} -export interface ListBoxItemProps extends RenderProps, LinkDOMProps, HoverEvents, PressEvents, FocusEvents, Omit, 'onClick'> { +export interface ListBoxItemProps extends Omit, 'render'>, PossibleLinkDOMRenderProps<'div', ListBoxItemRenderProps>, LinkDOMProps, HoverEvents, PressEvents, FocusEvents, Omit, 'onClick'> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-ListBoxItem' @@ -394,7 +398,7 @@ export const ListBoxItem = /*#__PURE__*/ createLeafComponent(ItemNode, function } let isDragging = dragState && dragState.isDragging(item.key); - let renderProps = useRenderProps({ + let renderProps = useRenderProps({ ...props, id: undefined, children: props.children, @@ -416,13 +420,12 @@ export const ListBoxItem = /*#__PURE__*/ createLeafComponent(ItemNode, function } }, [item.textValue]); - let ElementType: React.ElementType = props.href ? 'a' : 'div'; - + let ElementType = props.href ? dom.a : dom.div; let DOMProps = filterDOMProps(props as any, {global: true}); delete DOMProps.id; delete DOMProps.onClick; - if (ElementType === 'a' && optionProps.tabIndex == null) { + if (props.href && optionProps.tabIndex == null) { optionProps.tabIndex = -1; } @@ -496,10 +499,9 @@ function ListBoxDropIndicator(props: ListBoxDropIndicatorProps, ref: ForwardedRe }); return ( -
    } data-drop-target={isDropTarget || undefined} /> @@ -508,7 +510,7 @@ function ListBoxDropIndicator(props: ListBoxDropIndicatorProps, ref: ForwardedRe const ListBoxDropIndicatorForwardRef = forwardRef(ListBoxDropIndicator); -export interface ListBoxLoadMoreItemProps extends Omit, StyleProps, GlobalDOMAttributes { +export interface ListBoxLoadMoreItemProps extends Omit, StyleProps, DOMRenderProps<'div', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-ListBoxLoadMoreItem' @@ -541,7 +543,7 @@ export const ListBoxLoadMoreItem = createLeafComponent(LoaderNode, function List id: undefined, children: item.rendered, defaultClassName: 'react-aria-ListBoxLoadingIndicator', - values: null + values: undefined }); let optionProps = { @@ -560,15 +562,14 @@ export const ListBoxLoadMoreItem = createLeafComponent(LoaderNode, function List
    {isLoading && renderProps.children && ( -
    }> {renderProps.children} -
    + )} ); diff --git a/packages/react-aria-components/src/Menu.tsx b/packages/react-aria-components/src/Menu.tsx index 5718c4841fb..994df7d3932 100644 --- a/packages/react-aria-components/src/Menu.tsx +++ b/packages/react-aria-components/src/Menu.tsx @@ -17,6 +17,9 @@ import { ClassNameOrFunction, ContextValue, DEFAULT_SLOT, + dom, + DOMRenderProps, + PossibleLinkDOMRenderProps, Provider, RenderProps, SlotProps, @@ -236,9 +239,9 @@ function MenuInner({props, collection, menuRef: ref}: MenuInne let {isVirtualized, CollectionRoot} = useContext(CollectionRendererContext); let {menuProps} = useMenu({...props, isVirtualized, onClose: props.onClose || triggerState?.close}, state, ref); let renderProps = useRenderProps({ + ...props, + children: undefined, defaultClassName: 'react-aria-Menu', - className: props.className, - style: props.style, values: { isEmpty: state.collection.size === 0 } @@ -259,7 +262,7 @@ function MenuInner({props, collection, menuRef: ref}: MenuInne return ( -
    } slot={props.slot || undefined} @@ -288,12 +291,12 @@ function MenuInner({props, collection, menuRef: ref}: MenuInne {emptyState} -
    +
    ); } -export interface MenuSectionProps extends SectionProps, MultipleSelection { +export interface MenuSectionProps extends SectionProps, MultipleSelection, DOMRenderProps<'section', undefined> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-MenuSection' @@ -343,10 +346,13 @@ function MenuSectionInner(props: MenuSectionProps, ref: For 'aria-label': section.props['aria-label'] ?? undefined }); let renderProps = useRenderProps({ + ...props, + id: undefined, + children: undefined, defaultClassName: className, className: section.props?.className, style: section.props?.style, - values: {} + values: undefined }); let parent = useContext(SelectionManagerContext)!; @@ -359,7 +365,7 @@ function MenuSectionInner(props: MenuSectionProps, ref: For delete DOMProps.id; return ( -
    (props: MenuSectionProps, ref: For ]}> -
    + ); } @@ -394,7 +400,7 @@ export interface MenuItemRenderProps extends ItemRenderProps { isOpen: boolean } -export interface MenuItemProps extends RenderProps, LinkDOMProps, HoverEvents, FocusEvents, PressEvents, Omit, 'onClick'> { +export interface MenuItemProps extends Omit, 'render'>, PossibleLinkDOMRenderProps<'div', MenuItemRenderProps>, LinkDOMProps, HoverEvents, FocusEvents, PressEvents, Omit, 'onClick'> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-MenuItem' @@ -438,7 +444,7 @@ export const MenuItem = /*#__PURE__*/ createLeafComponent(ItemNode, function Men let {hoverProps, isHovered} = useHover({ isDisabled: states.isDisabled }); - let renderProps = useRenderProps({ + let renderProps = useRenderProps({ ...props, id: undefined, children: item.rendered, @@ -454,7 +460,7 @@ export const MenuItem = /*#__PURE__*/ createLeafComponent(ItemNode, function Men } }); - let ElementType: React.ElementType = props.href ? 'a' : 'div'; + let ElementType = props.href ? dom.a : dom.div; let DOMProps = filterDOMProps(props as any, {global: true}); delete DOMProps.id; delete DOMProps.onClick; diff --git a/packages/react-aria-components/src/Meter.tsx b/packages/react-aria-components/src/Meter.tsx index 0f8fbecee7b..2d2999dcaca 100644 --- a/packages/react-aria-components/src/Meter.tsx +++ b/packages/react-aria-components/src/Meter.tsx @@ -15,6 +15,7 @@ import {clamp} from '@react-stately/utils'; import { ClassNameOrFunction, ContextValue, + dom, RenderProps, SlotProps, useContextProps, @@ -83,10 +84,10 @@ export const Meter = /*#__PURE__*/ (forwardRef as forwardRefType)(function Meter let DOMProps = filterDOMProps(props, {global: true}); return ( -
    + {renderProps.children} -
    + ); }); diff --git a/packages/react-aria-components/src/Modal.tsx b/packages/react-aria-components/src/Modal.tsx index 5aeccea36a5..e5954ce7d33 100644 --- a/packages/react-aria-components/src/Modal.tsx +++ b/packages/react-aria-components/src/Modal.tsx @@ -14,6 +14,7 @@ import {AriaModalOverlayProps, DismissButton, Overlay, useIsSSR, useModalOverlay import { ClassNameOrFunction, ContextValue, + dom, Provider, RenderProps, SlotProps, @@ -200,7 +201,7 @@ function ModalOverlayInner({UNSTABLE_portalContainer, ...props}: ModalOverlayInn return ( -
    {renderProps.children} -
    +
    ); } @@ -246,7 +247,7 @@ function ModalContent(props: ModalContentProps) { }); return ( -
    } {renderProps.children} -
    + ); } diff --git a/packages/react-aria-components/src/NumberField.tsx b/packages/react-aria-components/src/NumberField.tsx index 61b5329c4a3..d63df474bfa 100644 --- a/packages/react-aria-components/src/NumberField.tsx +++ b/packages/react-aria-components/src/NumberField.tsx @@ -15,6 +15,7 @@ import {ButtonContext} from './Button'; import { ClassNameOrFunction, ContextValue, + dom, Provider, RACValidation, removeDataAttributes, @@ -137,7 +138,7 @@ export const NumberField = /*#__PURE__*/ (forwardRef as forwardRefType)(function }], [FieldErrorContext, validation] ]}> -
    , 'className' | 'style' | 'children'>, RenderProps, DOMProps { +export interface OverlayArrowProps extends Omit, 'className' | 'style' | 'render' | 'children'>, RenderProps, DOMProps { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-OverlayArrow' @@ -77,7 +78,7 @@ export const OverlayArrow = /*#__PURE__*/ (forwardRef as forwardRefType)(functio let DOMProps = filterDOMProps(props); return ( -
    -
    + ); // If this is a root popover, render an extra div to act as the portal container for submenus/subdialogs. diff --git a/packages/react-aria-components/src/ProgressBar.tsx b/packages/react-aria-components/src/ProgressBar.tsx index 758c593eac1..1599f3cb6bc 100644 --- a/packages/react-aria-components/src/ProgressBar.tsx +++ b/packages/react-aria-components/src/ProgressBar.tsx @@ -15,6 +15,7 @@ import {clamp} from '@react-stately/utils'; import { ClassNameOrFunction, ContextValue, + dom, RenderProps, SlotProps, useContextProps, @@ -91,10 +92,10 @@ export const ProgressBar = forwardRef(function ProgressBar(props: ProgressBarPro let DOMProps = filterDOMProps(props, {global: true}); return ( -
    + {renderProps.children} -
    + ); }); diff --git a/packages/react-aria-components/src/RadioGroup.tsx b/packages/react-aria-components/src/RadioGroup.tsx index eca6629f434..2ddf845e4a0 100644 --- a/packages/react-aria-components/src/RadioGroup.tsx +++ b/packages/react-aria-components/src/RadioGroup.tsx @@ -14,6 +14,7 @@ import {AriaRadioGroupProps, AriaRadioProps, HoverEvents, Orientation, useFocusR import { ClassNameOrFunction, ContextValue, + dom, Provider, RACValidation, removeDataAttributes, @@ -42,7 +43,7 @@ export interface RadioGroupProps extends Omit } -export interface RadioProps extends Omit, HoverEvents, RenderProps, SlotProps, Omit, 'onClick'> { +export interface RadioProps extends Omit, HoverEvents, RenderProps, SlotProps, Omit, 'onClick'> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Radio' @@ -175,7 +176,7 @@ export const RadioGroup = /*#__PURE__*/ (forwardRef as forwardRefType)(function let DOMProps = filterDOMProps(props, {global: true}); return ( -
    -
    + ); }); @@ -249,7 +250,7 @@ export const Radio = /*#__PURE__*/ (forwardRef as forwardRefType)(function Radio delete DOMProps.onClick; return ( - + ); }); diff --git a/packages/react-aria-components/src/SearchField.tsx b/packages/react-aria-components/src/SearchField.tsx index 4a86b4f4ace..957c22a5cce 100644 --- a/packages/react-aria-components/src/SearchField.tsx +++ b/packages/react-aria-components/src/SearchField.tsx @@ -15,6 +15,7 @@ import {ButtonContext} from './Button'; import { ClassNameOrFunction, ContextValue, + dom, Provider, RACValidation, removeDataAttributes, @@ -120,7 +121,7 @@ export const SearchField = /*#__PURE__*/ createHideableComponent(function Search delete DOMProps.id; return ( -
    {renderProps.children} -
    + ); }); diff --git a/packages/react-aria-components/src/Select.tsx b/packages/react-aria-components/src/Select.tsx index e28181646fd..ded3a340eee 100644 --- a/packages/react-aria-components/src/Select.tsx +++ b/packages/react-aria-components/src/Select.tsx @@ -15,6 +15,7 @@ import {ButtonContext} from './Button'; import { ClassNameOrFunction, ContextValue, + dom, Provider, RACValidation, removeDataAttributes, @@ -224,7 +225,7 @@ function SelectInner({props, selectRef: ref, collection}: Sele }], [FieldErrorContext, validation] ]}> -
    ({props, selectRef: ref, collection}: Sele -
    + ); } @@ -262,7 +263,7 @@ export interface SelectValueRenderProps { state: SelectState } -export interface SelectValueProps extends Omit, keyof RenderProps>, RenderProps> { +export interface SelectValueProps extends Omit, keyof RenderProps>, RenderProps, 'span'> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-SelectValue' @@ -347,11 +348,11 @@ export const SelectValue = /*#__PURE__*/ createHideableComponent(function Select let DOMProps = filterDOMProps(props, {global: true}); return ( - + {/* clear description and error message slots */} {renderProps.children} - + ); }); diff --git a/packages/react-aria-components/src/Separator.tsx b/packages/react-aria-components/src/Separator.tsx index 48d26b282e6..045d77b5e77 100644 --- a/packages/react-aria-components/src/Separator.tsx +++ b/packages/react-aria-components/src/Separator.tsx @@ -12,12 +12,12 @@ import {SeparatorProps as AriaSeparatorProps, useSeparator} from 'react-aria'; import {BaseCollection, CollectionNode, createLeafComponent} from '@react-aria/collections'; -import {ContextValue, SlotProps, StyleProps, useContextProps} from './utils'; +import {ContextValue, dom, DOMRenderProps, SlotProps, StyleProps, useContextProps} from './utils'; import {filterDOMProps, mergeProps} from '@react-aria/utils'; import {GlobalDOMAttributes} from '@react-types/shared'; -import React, {createContext, ElementType, ForwardedRef} from 'react'; +import React, {createContext, ForwardedRef} from 'react'; -export interface SeparatorProps extends AriaSeparatorProps, StyleProps, SlotProps, GlobalDOMAttributes { +export interface SeparatorProps extends AriaSeparatorProps, StyleProps, SlotProps, DOMRenderProps<'hr' | 'div', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-Separator' @@ -49,11 +49,13 @@ export const Separator = /*#__PURE__*/ createLeafComponent(SeparatorNode, functi [props, ref] = useContextProps(props, ref, SeparatorContext); let {elementType, orientation, style, className, slot, ...otherProps} = props; - let Element = (elementType as ElementType) || 'hr'; + let Element = elementType || 'hr'; if (Element === 'hr' && orientation === 'vertical') { Element = 'div'; } + let ElementType = dom[Element]; + let {separatorProps} = useSeparator({ ...otherProps, elementType, @@ -63,7 +65,8 @@ export const Separator = /*#__PURE__*/ createLeafComponent(SeparatorNode, functi let DOMProps = filterDOMProps(props, {global: true}); return ( - ) { - let {name, isVisible = true, children, className, style, ...divProps} = props; + let {name, isVisible = true, children, className, style, render, ...divProps} = props; let [state, setState] = useState(isVisible ? 'visible' : 'hidden'); let scopeRef = useContext(SharedElementContext); if (!scopeRef) { @@ -164,6 +164,7 @@ export const SharedElement = forwardRef(function SharedElement(props: SharedElem children, className, style, + render, values: { isEntering: state === 'entering', isExiting: state === 'exiting' @@ -175,7 +176,7 @@ export const SharedElement = forwardRef(function SharedElement(props: SharedElem } return ( -
    -
    , GlobalDOMAttributes { +export interface SliderOutputProps extends RenderProps, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-SliderOutput' @@ -125,12 +126,13 @@ interface SliderOutputContextValue extends Omit) { [props, ref] = useContextProps(props, ref, SliderOutputContext); - let {children, style, className, ...otherProps} = props; + let {children, style, className, render, ...otherProps} = props; let state = useContext(SliderStateContext)!; let renderProps = useRenderProps({ className, style, children, + render, defaultChildren: state.getThumbValueLabel(0), defaultClassName: 'react-aria-SliderOutput', values: { @@ -141,7 +143,7 @@ export const SliderOutput = /*#__PURE__*/ (forwardRef as forwardRefType)(functio }); return ( - {renderProps.children} -
    + ); }); diff --git a/packages/react-aria-components/src/Switch.tsx b/packages/react-aria-components/src/Switch.tsx index 6f1e20c71f9..b61104cc9ca 100644 --- a/packages/react-aria-components/src/Switch.tsx +++ b/packages/react-aria-components/src/Switch.tsx @@ -12,20 +12,21 @@ import {AriaSwitchProps, HoverEvents, mergeProps, useFocusRing, useHover, useSwitch, VisuallyHidden} from 'react-aria'; import { - ClassNameOrFunction, - ContextValue, - removeDataAttributes, - RenderProps, - SlotProps, - useContextProps, - useRenderProps + ClassNameOrFunction, + ContextValue, + dom, + removeDataAttributes, + RenderProps, + SlotProps, + useContextProps, + useRenderProps } from './utils'; import {filterDOMProps, mergeRefs, useObjectRef} from '@react-aria/utils'; import {forwardRefType, GlobalDOMAttributes, RefObject} from '@react-types/shared'; import React, {createContext, ForwardedRef, forwardRef} from 'react'; import {ToggleState, useToggleState} from 'react-stately'; -export interface SwitchProps extends Omit, HoverEvents, RenderProps, SlotProps, Omit, 'onClick'> { +export interface SwitchProps extends Omit, HoverEvents, RenderProps, SlotProps, Omit, 'onClick'> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Switch' @@ -125,7 +126,7 @@ export const Switch = /*#__PURE__*/ (forwardRef as forwardRefType)(function Swit delete DOMProps.onClick; return ( - + ); }); diff --git a/packages/react-aria-components/src/Table.tsx b/packages/react-aria-components/src/Table.tsx index 81b6e4dbebd..e0f5fcf67a8 100644 --- a/packages/react-aria-components/src/Table.tsx +++ b/packages/react-aria-components/src/Table.tsx @@ -7,7 +7,9 @@ import { ClassNameOrFunction, ContextValue, DEFAULT_SLOT, + dom, DOMProps, + DOMRenderProps, Provider, RenderProps, SlotProps, @@ -218,7 +220,7 @@ interface ResizableTableContainerContextValue { const ResizableTableContainerContext = createContext(null); -export interface ResizableTableContainerProps extends DOMProps, GlobalDOMAttributes { +export interface ResizableTableContainerProps extends DOMProps, DOMRenderProps<'div', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-ResizableTableContainer' @@ -283,7 +285,8 @@ export const ResizableTableContainer = forwardRef(function ResizableTableContain }), [tableRef, width, props.onResizeStart, props.onResize, props.onResizeEnd]); return ( -
    {props.children} -
    + ); }); @@ -322,7 +325,7 @@ export interface TableRenderProps { state: TableState } -export interface TableProps extends Omit, 'children'>, StyleRenderProps, SlotProps, AriaLabelingProps, GlobalDOMAttributes { +export interface TableProps extends Omit, 'children'>, StyleRenderProps, SlotProps, AriaLabelingProps, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Table' @@ -387,9 +390,9 @@ interface TableInnerProps { let TableElementType = forwardRef(function TableElementType(props: any, ref: ForwardedRef) { let {isVirtualized} = useContext(CollectionRendererContext); if (isVirtualized) { - return
    ; + return ; } - return ; + return ; }); function TableInner({props, forwardedRef: ref, selectionState, collection}: TableInnerProps) { @@ -475,8 +478,8 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl let {focusProps, isFocused, isFocusVisible} = useFocusRing(); let renderProps = useRenderProps({ - className: props.className, - style: props.style, + ...props, + children: undefined, defaultClassName: 'react-aria-Table', values: { isDropTarget: isRootDropTarget, @@ -567,7 +570,7 @@ export interface TableHeaderRenderProps { isHovered: boolean } -export interface TableHeaderProps extends StyleRenderProps, HoverEvents, GlobalDOMAttributes { +export interface TableHeaderProps extends StyleRenderProps, HoverEvents, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-TableHeader' @@ -588,9 +591,9 @@ class TableHeaderNode extends CollectionNode { let THeadElementType = forwardRef(function THeadElementType(props: any, ref: ForwardedRef) { let {isVirtualized} = useContext(CollectionRendererContext); if (isVirtualized) { - return
    ; + return ; } - return
    ; + return ; }); /** @@ -620,8 +623,8 @@ export const TableHeader = /*#__PURE__*/ createBranchComponent( }); let renderProps = useRenderProps({ - className: props.className, - style: props.style, + ...props, + children: undefined, defaultClassName: 'react-aria-TableHeader', values: { isHovered @@ -722,7 +725,7 @@ export interface ColumnRenderProps { startResize(): void } -export interface ColumnProps extends RenderProps, GlobalDOMAttributes { +export interface ColumnProps extends RenderProps, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Column' @@ -753,9 +756,9 @@ class TableColumnNode extends CollectionNode { let ColumnElementType = forwardRef(function ColumnElementType(props: any, ref: ForwardedRef) { let {isVirtualized} = useContext(CollectionRendererContext); if (isVirtualized) { - return
    ; + return ; } - return
    ; + return ; }); /** @@ -1093,7 +1096,7 @@ export interface RowRenderProps extends ItemRenderProps { id?: Key } -export interface RowProps extends StyleRenderProps, LinkDOMProps, HoverEvents, PressEvents, Omit, 'onClick'> { +export interface RowProps extends StyleRenderProps, LinkDOMProps, HoverEvents, PressEvents, Omit, 'onClick'> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Row' @@ -1140,9 +1143,9 @@ class TableRowNode extends CollectionNode { let TableRowElementType = forwardRef(function TableRowElementType(props: any, ref: ForwardedRef) { let {isVirtualized} = useContext(CollectionRendererContext); if (isVirtualized) { - return
    ; + return ; } - return
    ; + return ; }); /** @@ -1328,7 +1331,7 @@ export interface CellRenderProps { colIndex?: number | null } -export interface CellProps extends RenderProps, GlobalDOMAttributes { +export interface CellProps extends RenderProps, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Cell' @@ -1349,9 +1352,9 @@ class TableCellNode extends CollectionNode { let TableCellElementType = forwardRef(function TableCellElementType(props: any, ref: ForwardedRef) { let {isVirtualized} = useContext(CollectionRendererContext); if (isVirtualized) { - return
    ; + return ; } - return
    ; + return ; }); let TableDropIndicatorTDElementType = forwardRef(function TableDropIndicatorTDElementType(props: any, ref: ForwardedRef) { let {isVirtualized} = useContext(CollectionRendererContext); if (isVirtualized) { - return
    ; + return ; } - return
    ; + return ; }); /** @@ -964,7 +967,7 @@ export const ColumnResizer = forwardRef(function ColumnResizer(props: ColumnResi let DOMProps = filterDOMProps(props, {global: true}); return ( -
    {isResizing && isMouseDown && ReactDOM.createPortal(
    , document.body)} -
    + ); }); @@ -995,7 +998,7 @@ export interface TableBodyRenderProps { isDropTarget: boolean } -export interface TableBodyProps extends Omit, 'disabledKeys'>, StyleRenderProps, GlobalDOMAttributes { +export interface TableBodyProps extends Omit, 'disabledKeys'>, StyleRenderProps, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-TableBody' @@ -1012,9 +1015,9 @@ class TableBodyNode extends FilterableNode { let TableBodyElementType = forwardRef(function TableBodyElementType(props: any, ref: ForwardedRef) { let {isVirtualized} = useContext(CollectionRendererContext); if (isVirtualized) { - return
    ; + return ; } - return
    ; + return ; }); /** @@ -1438,16 +1441,16 @@ interface TableDropIndicatorProps extends DropIndicatorProps, GlobalDOMAttribute let TableDropIndicatorRowElementType = forwardRef(function TableDropIndicatorRowElementType(props: any, ref: ForwardedRef) { let {isVirtualized} = useContext(CollectionRendererContext); if (isVirtualized) { - return
    ; + return ; } - return
    ; + return ; }); function TableDropIndicator(props: TableDropIndicatorProps, ref: ForwardedRef) { @@ -1517,7 +1520,7 @@ function RootDropIndicator() { ); } -export interface TableLoadMoreItemProps extends Omit, StyleProps, GlobalDOMAttributes { +export interface TableLoadMoreItemProps extends Omit, StyleProps, DOMRenderProps<'tr' | 'div', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-TableLoadMoreItem' @@ -1553,7 +1556,7 @@ export const TableLoadMoreItem = createLeafComponent(LoaderNode, function TableL id: undefined, children: item.rendered, defaultClassName: 'react-aria-TableLoadingIndicator', - values: null + values: undefined }); let rowProps = {}; let rowHeaderProps = {}; diff --git a/packages/react-aria-components/src/Tabs.tsx b/packages/react-aria-components/src/Tabs.tsx index 98626632a50..994934d3609 100644 --- a/packages/react-aria-components/src/Tabs.tsx +++ b/packages/react-aria-components/src/Tabs.tsx @@ -12,7 +12,7 @@ import {AriaLabelingProps, FocusEvents, forwardRefType, GlobalDOMAttributes, HoverEvents, Key, LinkDOMProps, PressEvents, RefObject} from '@react-types/shared'; import {AriaTabListProps, AriaTabPanelProps, mergeProps, Orientation, useFocusRing, useHover, useTab, useTabList, useTabPanel} from 'react-aria'; -import {ClassNameOrFunction, ContextValue, Provider, RenderProps, SlotProps, StyleProps, StyleRenderProps, useContextProps, useRenderProps, useSlottedContext} from './utils'; +import {ClassNameOrFunction, ContextValue, dom, DOMRenderProps, PossibleLinkDOMRenderProps, Provider, RenderProps, SlotProps, StyleProps, StyleRenderProps, useContextProps, useRenderProps, useSlottedContext} from './utils'; import {Collection, CollectionBuilder, CollectionNode, createHideableComponent, createLeafComponent} from '@react-aria/collections'; import {CollectionProps, CollectionRendererContext, DefaultCollectionRenderer, usePersistedKeys} from './Collection'; import {filterDOMProps, inertValue, useEnterAnimation, useExitAnimation, useLayoutEffect, useObjectRef} from '@react-aria/utils'; @@ -57,7 +57,7 @@ export interface TabListRenderProps { state: TabListState } -export interface TabProps extends RenderProps, AriaLabelingProps, LinkDOMProps, HoverEvents, FocusEvents, PressEvents, Omit, 'onClick'> { +export interface TabProps extends Omit, 'render'>, PossibleLinkDOMRenderProps<'div', TabRenderProps>, AriaLabelingProps, LinkDOMProps, HoverEvents, FocusEvents, PressEvents, Omit, 'onClick'> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Tab' @@ -199,7 +199,7 @@ function TabsInner({props, tabsRef: ref, collection}: TabsInnerProps) { let DOMProps = filterDOMProps(props, {global: true}); return ( -
    {renderProps.children} -
    + ); } @@ -260,14 +260,14 @@ function TabListInner({props, forwardedRef: ref}: TabListInner delete DOMProps.id; return ( -
    -
    + ); } @@ -290,7 +290,7 @@ export const Tab = /*#__PURE__*/ createLeafComponent(TabItemNode, (props: TabPro onHoverChange: props.onHoverChange }); - let renderProps = useRenderProps({ + let renderProps = useRenderProps({ ...props, id: undefined, children: item.rendered, @@ -305,7 +305,7 @@ export const Tab = /*#__PURE__*/ createLeafComponent(TabItemNode, (props: TabPro } }); - let ElementType: React.ElementType = item.props.href ? 'a' : 'div'; + let ElementType = item.props.href ? dom.a : dom.div; let DOMProps = filterDOMProps(props as any, {global: true}); delete DOMProps.id; delete DOMProps.onClick; @@ -327,7 +327,7 @@ export const Tab = /*#__PURE__*/ createLeafComponent(TabItemNode, (props: TabPro ); }); -export interface TabPanelsProps extends Omit, 'disabledKeys'>, StyleProps, GlobalDOMAttributes { +export interface TabPanelsProps extends Omit, 'disabledKeys'>, StyleProps, DOMRenderProps<'div', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-TabPanels' @@ -398,12 +398,13 @@ export const TabPanels = /*#__PURE__*/ createHideableComponent(function TabPanel delete DOMProps.id; return ( -
    -
    + ); }); @@ -469,7 +470,7 @@ function TabPanelInner(props: TabPanelProps & {tabPanelRef: RefObject - + ); } diff --git a/packages/react-aria-components/src/TagGroup.tsx b/packages/react-aria-components/src/TagGroup.tsx index 1497ab16841..7df9f7b338e 100644 --- a/packages/react-aria-components/src/TagGroup.tsx +++ b/packages/react-aria-components/src/TagGroup.tsx @@ -15,7 +15,9 @@ import {ButtonContext} from './Button'; import { ClassNameOrFunction, ContextValue, + dom, DOMProps, + DOMRenderProps, Provider, RenderProps, SlotProps, @@ -37,7 +39,7 @@ import {SelectionIndicatorContext} from './SelectionIndicator'; import {SharedElementTransition} from './SharedElementTransition'; import {TextContext} from './Text'; -export interface TagGroupProps extends Omit, 'children' | 'items' | 'label' | 'description' | 'errorMessage' | 'keyboardDelegate'>, DOMProps, SlotProps, GlobalDOMAttributes { +export interface TagGroupProps extends Omit, 'children' | 'items' | 'label' | 'description' | 'errorMessage' | 'keyboardDelegate'>, DOMProps, SlotProps, DOMRenderProps<'div', undefined>, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. * @default 'react-aria-TagGroup' @@ -67,7 +69,7 @@ export interface TagListRenderProps { state: ListState } -export interface TagListProps extends Omit, 'disabledKeys'>, StyleRenderProps, GlobalDOMAttributes { +export interface TagListProps extends Omit, 'disabledKeys'>, StyleRenderProps, GlobalDOMAttributes { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-TagList' @@ -97,7 +99,7 @@ export const TagGroup = /*#__PURE__*/ (forwardRef as forwardRefType)(function Ta interface TagGroupInnerProps { props: TagGroupProps & SelectableCollectionContextValue, forwardedRef: ForwardedRef, - collection + collection: any } function TagGroupInner({props, forwardedRef: ref, collection}: TagGroupInnerProps) { @@ -133,7 +135,8 @@ function TagGroupInner({props, forwardedRef: ref, collection}: }, filteredState, tagListRef); return ( -
    ({props, forwardedRef: ref, collection}: ]}> {props.children} -
    + ); } @@ -186,8 +189,8 @@ function TagListInner({props, forwardedRef}: TagListInnerProps state }; let renderProps = useRenderProps({ - className: props.className, - style: props.style, + ...props, + children: undefined, defaultClassName: 'react-aria-TagList', values: renderValues }); @@ -196,7 +199,7 @@ function TagListInner({props, forwardedRef}: TagListInnerProps let DOMProps = filterDOMProps(props, {global: true}); return ( -
    ({props, forwardedRef}: TagListInnerProps ? props.renderEmptyState(renderValues) : } -
    + ); } @@ -219,7 +222,7 @@ export interface TagRenderProps extends Omit, LinkDOMProps, HoverEvents, FocusEvents, PressEvents, Omit, 'onClick'> { +export interface TagProps extends RenderProps, LinkDOMProps, HoverEvents, FocusEvents, PressEvents, Omit, 'onClick'> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-Tag' @@ -277,7 +280,7 @@ export const Tag = /*#__PURE__*/ createLeafComponent(ItemNode, (props: TagProps, delete DOMProps.onClick; return ( -
    - + ); }); diff --git a/packages/react-aria-components/src/Text.tsx b/packages/react-aria-components/src/Text.tsx index 022dff3b452..737952dab9f 100644 --- a/packages/react-aria-components/src/Text.tsx +++ b/packages/react-aria-components/src/Text.tsx @@ -10,10 +10,10 @@ * governing permissions and limitations under the License. */ -import {ContextValue, useContextProps} from './utils'; +import {ContextValue, dom, DOMRenderProps, useContextProps} from './utils'; import React, {createContext, ForwardedRef, forwardRef, HTMLAttributes} from 'react'; -export interface TextProps extends HTMLAttributes { +export interface TextProps extends HTMLAttributes, DOMRenderProps { elementType?: string } @@ -21,7 +21,8 @@ export const TextContext = createContext>({ export const Text = forwardRef(function Text(props: TextProps, ref: ForwardedRef) { [props, ref] = useContextProps(props, ref, TextContext); - let {elementType: ElementType = 'span', ...domProps} = props; + let {elementType = 'span', ...domProps} = props; + let ElementType = dom[elementType]; // @ts-ignore return ; }); diff --git a/packages/react-aria-components/src/TextArea.tsx b/packages/react-aria-components/src/TextArea.tsx index 58dc97ff8df..c0ac27fded5 100644 --- a/packages/react-aria-components/src/TextArea.tsx +++ b/packages/react-aria-components/src/TextArea.tsx @@ -1,6 +1,7 @@ import { ClassNameOrFunction, ContextValue, + dom, StyleRenderProps, useContextProps, useRenderProps @@ -9,7 +10,7 @@ import {HoverEvents, mergeProps, useFocusRing, useHover} from 'react-aria'; import {InputRenderProps} from './Input'; import React, {createContext, ForwardedRef, forwardRef, TextareaHTMLAttributes} from 'react'; -export interface TextAreaProps extends Omit, 'className' | 'style'>, HoverEvents, StyleRenderProps { +export interface TextAreaProps extends Omit, 'className' | 'style'>, HoverEvents, StyleRenderProps { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-TextArea' @@ -51,7 +52,7 @@ export const TextArea = forwardRef(function TextArea(props: TextAreaProps, ref: }); return ( -