Skip to content

Commit 2dfdb41

Browse files
committed
progress
1 parent 8ae7cab commit 2dfdb41

File tree

9 files changed

+51
-29
lines changed

9 files changed

+51
-29
lines changed

eslint.config.mjs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -445,29 +445,6 @@ export default [{
445445
"jsdoc/require-jsdoc": OFF,
446446
"jsdoc/require-description": OFF,
447447
},
448-
}, {
449-
files: [
450-
"packages/**/*.ts",
451-
"packages/**/*.tsx"
452-
],
453-
454-
rules: {
455-
"@typescript-eslint/explicit-module-boundary-types": ERROR,
456-
},
457-
}, {
458-
files: [
459-
"**/dev/**",
460-
"**/test/**",
461-
"**/stories/**",
462-
"**/docs/**",
463-
"**/chromatic/**",
464-
"**/chromatic-fc/**",
465-
"**/__tests__/**"
466-
],
467-
468-
rules: {
469-
"@typescript-eslint/explicit-module-boundary-types": OFF,
470-
},
471448
}, {
472449
files: [
473450
"packages/@react-aria/focus/src/**/*.ts",
@@ -504,4 +481,4 @@ export default [{
504481
rules: {
505482
"react/react-in-jsx-scope": OFF,
506483
},
507-
}];
484+
}];

packages/@react-spectrum/s2/src/ColorField.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {FormContext, useFormProps} from './Form';
2323
import {GlobalDOMAttributes, HelpTextProps, SpectrumLabelableProps} from '@react-types/shared';
2424
import {style} from '../style' with {type: 'macro'};
2525
import {TextFieldRef} from '@react-types/textfield';
26+
import {usePlaceholderWarning} from './placeholder-utils';
2627
import {useSpectrumContextProps} from './useSpectrumContextProps';
2728

2829
export interface ColorFieldProps extends Omit<AriaColorFieldProps, 'children' | 'className' | 'style' | keyof GlobalDOMAttributes>, StyleProps, SpectrumLabelableProps, HelpTextProps {
@@ -75,6 +76,8 @@ export const ColorField = forwardRef(function ColorField(props: ColorFieldProps,
7576
}
7677
}));
7778

79+
usePlaceholderWarning(props.placeholder, 'ColorField', inputRef);
80+
7881
return (
7982
<AriaColorField
8083
{...fieldProps}

packages/@react-spectrum/s2/src/ComboBox.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import {pressScale} from './pressScale';
6464
import {ProgressCircle} from './ProgressCircle';
6565
import {TextFieldRef} from '@react-types/textfield';
6666
import {useLocalizedStringFormatter} from '@react-aria/i18n';
67+
import {usePlaceholderWarning} from './placeholder-utils';
6768
import {useScale} from './utils';
6869
import {useSpectrumContextProps} from './useSpectrumContextProps';
6970

@@ -580,6 +581,7 @@ const ComboboxInner = forwardRef(function ComboboxInner(props: ComboBoxProps<any
580581
);
581582
}
582583
let scale = useScale();
584+
usePlaceholderWarning(props.placeholder, 'ComboBox', inputRef);
583585

584586
return (
585587
<>

packages/@react-spectrum/s2/src/NumberField.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {GlobalDOMAttributes, HelpTextProps, SpectrumLabelableProps} from '@react
3333
import {pressScale} from './pressScale';
3434
import {TextFieldRef} from '@react-types/textfield';
3535
import {useButton, useFocusRing, useHover} from 'react-aria';
36+
import {usePlaceholderWarning} from './placeholder-utils';
3637
import {useSpectrumContextProps} from './useSpectrumContextProps';
3738

3839

@@ -177,6 +178,7 @@ export const NumberField = forwardRef(function NumberField(props: NumberFieldPro
177178
}
178179
}));
179180

181+
usePlaceholderWarning(props.placeholder, 'NumberField', inputRef);
180182

181183
return (
182184
<AriaNumberField

packages/@react-spectrum/s2/src/SearchField.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {IconContext} from './Icon';
2929
import {raw} from '../style/style-macro' with {type: 'macro'};
3030
import SearchIcon from '../s2wf-icons/S2_Icon_Search_20_N.svg';
3131
import {TextFieldRef} from '@react-types/textfield';
32+
import {usePlaceholderWarning} from './placeholder-utils';
3233
import {useSpectrumContextProps} from './useSpectrumContextProps';
3334

3435
export interface SearchFieldProps extends Omit<AriaSearchFieldProps, 'className' | 'style' | 'children' | keyof GlobalDOMAttributes>, StyleProps, SpectrumLabelableProps, HelpTextProps {
@@ -81,6 +82,8 @@ export const SearchField = /*#__PURE__*/ forwardRef(function SearchField(props:
8182
}
8283
}));
8384

85+
usePlaceholderWarning(props.placeholder, 'SearchField', inputRef);
86+
8487
return (
8588
<AriaSearchField
8689
{...searchFieldProps}

packages/@react-spectrum/s2/src/TextField.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ import {createContext, forwardRef, ReactNode, Ref, useContext, useImperativeHand
2525
import {createFocusableRef} from '@react-spectrum/utils';
2626
import {FieldErrorIcon, FieldGroup, FieldLabel, HelpText, Input} from './Field';
2727
import {FormContext, useFormProps} from './Form';
28-
import {GlobalDOMAttributes, HelpTextProps, SpectrumLabelableProps} from '@react-types/shared';
28+
import {GlobalDOMAttributes, HelpTextProps, RefObject, SpectrumLabelableProps} from '@react-types/shared';
2929
import {mergeRefs} from '@react-aria/utils';
3030
import {style} from '../style' with {type: 'macro'};
3131
import {StyleString} from '../style/types';
3232
import {TextFieldRef} from '@react-types/textfield';
33+
import {usePlaceholderWarning} from './placeholder-utils';
3334
import {useSpectrumContextProps} from './useSpectrumContextProps';
3435

3536
export interface TextFieldProps extends Omit<AriaTextFieldProps, 'children' | 'className' | 'style' | keyof GlobalDOMAttributes>, StyleProps, SpectrumLabelableProps, HelpTextProps {
@@ -39,7 +40,6 @@ export interface TextFieldProps extends Omit<AriaTextFieldProps, 'children' | 'c
3940
* @default 'M'
4041
*/
4142
size?: 'S' | 'M' | 'L' | 'XL',
42-
// TODO: put warning about needing to provide this for cases where the text field is not focused and doesn't have text
4343
/**
4444
* Temporary text that occupies the text input when it is empty.
4545
*/
@@ -106,6 +106,8 @@ export const TextFieldBase = forwardRef(function TextFieldBase(props: TextFieldP
106106
...textFieldProps
107107
} = props;
108108

109+
usePlaceholderWarning(props.placeholder, 'TextField/Area', inputRef);
110+
109111
// Expose imperative interface for ref
110112
useImperativeHandle(ref, () => ({
111113
...createFocusableRef(domRef, inputRef),
@@ -185,10 +187,11 @@ function TextAreaInput() {
185187
input.style.alignSelf = prevAlignment;
186188
}
187189
};
190+
let {ref} = useSlottedContext(InputContext) ?? {};
188191

189192
return (
190193
<AriaTextArea
191-
ref={onHeightChange}
194+
ref={mergeRefs(onHeightChange, ref as RefObject<HTMLTextAreaElement | null>)}
192195
// Workaround for baseline alignment bug in Safari.
193196
// https://bugs.webkit.org/show_bug.cgi?id=142968
194197
placeholder={placeholder ?? ' '}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2025 Adobe. All rights reserved.
3+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License. You may obtain a copy
5+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under
8+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
* OF ANY KIND, either express or implied. See the License for the specific language
10+
* governing permissions and limitations under the License.
11+
*/
12+
13+
import {RefObject, useEffect} from 'react';
14+
import {useEffectEvent, useEvent} from '@react-aria/utils';
15+
16+
export function usePlaceholderWarning(placeholder: string | undefined, componentType: string, inputRef: RefObject<HTMLInputElement | null>): void {
17+
let checkPlaceholder = useEffectEvent((input: HTMLInputElement | null) => {
18+
if (!placeholder && input) {
19+
if (document.activeElement !== input && (!input.value || input.value === '') && process.env.NODE_ENV !== 'production') {
20+
console.warn(`Your ${componentType} is empty and not focused but doesn't have a placeholder. Please add one.`);
21+
}
22+
}
23+
});
24+
25+
useEffect(() => {
26+
checkPlaceholder(inputRef.current);
27+
}, [checkPlaceholder, inputRef]);
28+
29+
useEvent(inputRef, 'blur', (e) => checkPlaceholder(e.target as HTMLInputElement));
30+
}

packages/@react-spectrum/s2/stories/ColorField.stories.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ type Story = StoryObj<typeof ColorField>;
4343
export const Example: Story = {
4444
render: (args) => <ColorField {...args} />,
4545
args: {
46-
label: 'Color'
46+
label: 'Color',
47+
placeholder: '######'
4748
}
4849
};
4950

packages/@react-spectrum/s2/stories/TextField.stories.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ const meta: Meta<typeof TextField> = {
2828
label: {control: {type: 'text'}},
2929
description: {control: {type: 'text'}},
3030
errorMessage: {control: {type: 'text'}},
31-
contextualHelp: {table: {disable: true}}
31+
contextualHelp: {table: {disable: true}},
32+
placeholder: {control: {type: 'text', defaultValue: 'Enter a name'}}
3233
},
3334
title: 'TextField'
3435
};

0 commit comments

Comments
 (0)