-
Notifications
You must be signed in to change notification settings - Fork 1.3k
fix: ensure isReadonly
applies to all non-literal date segments
#7969
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
isReadonly
applies to all non-literal DateSegments
isReadonly
applies to all non-literal DateSegments
isReadonly
applies to all non-literal DateSegments
isReadonly
applies to all non-literal DateSegments
isReadonly
applies to all non-literal date segments
08e945b
to
6a6319c
Compare
6a6319c
to
3ed43ed
Compare
Hey, thanks for the code. Could you provide some tests/add a control to storybook? I'm not able to reproduce the issue. |
@snowystinger Here is the reproduction: https://codesandbox.io/p/devbox/floral-wind-2fx6pc?workspaceId=ws_nU6d6H4r59ATf4jbZ5rYc You can see that only the literal elements carry the
This causes a mismatch between the To be honest i feel like both |
I'm not sure why the literals have readonly at all, the control is disabled, and the literals aren't interactive to being with. In aria, disabled almost the same as not existing. So it seems to me that readonly is unnecessary and shouldn't even be appearing there unless the control has Maybe we should back up, what is the use case you're trying to build? |
@snowystinger No use case besides styling being difficult right now for |
@nwidynski Just to clarify, the expectation here would be that |
@LFDanLu Yep. We had expected |
@LFDanLu Anything else blocking here? |
The goal here is still a little confusing to me.
|
@snowystinger The problem with this test suite is that there is no
it('should support readonly state', () => {
let {getByRole} = render(
<DateField isReadOnly>
<Label>Birth date</Label>
<DateInput>
{segment => <DateSegment segment={segment} />}
</DateInput>
</DateField>
);
let group = getByRole('group');
for (let segment of [...group.children].filter(child => child.getAttribute('data-type') === 'segment')) {
expect(segment).toHaveAttribute('data-readonly');
}
for (let literal of [...group.children].filter(child => child.getAttribute('data-type') === 'literal')) {
expect(literal).toHaveAttribute('data-readonly');
}
}); |
doh, copy pasta strikes again, updated the tests to reflect that |
@snowystinger Does this suite pass on main? for (let segment of getAllByRole('spinbutton')) {
expect(segment).toHaveAttribute('data-readonly');
} This should fail in |
It's failing both on main and in this branch |
@snowystinger Ah, I see where the misunderstanding comes from. Our team is currently wondering why This can easily lead to subtle inconsistencies in the design system if styling with opacity for example and isn't aligned with the behavior of other RACs. If we can find a common ground here, I can wrap up the implementation. Our expectation looks like this: it('provides slots', () => {
let {getByRole, getAllByRole} = render(
<DateField data-foo="bar">
<Label>Birth date</Label>
<DateInput data-bar="foo">
{segment => <DateSegment segment={segment} data-test="test" />}
</DateInput>
<Text slot="description">Description</Text>
<Text slot="errorMessage">Error</Text>
</DateField>
);
let input = getByRole('group');
expect(input).toHaveTextContent('mm/dd/yyyy');
expect(input).toHaveAttribute('class', 'react-aria-DateInput');
expect(input).toHaveAttribute('data-bar', 'foo');
expect(input.closest('.react-aria-DateField')).toHaveAttribute('data-foo', 'bar');
expect(input).toHaveAttribute('aria-labelledby');
let label = document.getElementById(input.getAttribute('aria-labelledby'));
expect(label).toHaveAttribute('class', 'react-aria-Label');
expect(label).toHaveTextContent('Birth date');
expect(input).toHaveAttribute('aria-describedby');
expect(input.getAttribute('aria-describedby').split(' ').map(id => document.getElementById(id).textContent).join(' ')).toBe('Description Error');
for (let segment of getAllByRole('spinbutton')) {
expect(segment).toHaveAttribute('class', 'react-aria-DateSegment');
expect(segment).toHaveAttribute('data-placeholder', 'true');
expect(segment).toHaveAttribute('data-type');
expect(segment).toHaveAttribute('data-test', 'test');
expect(segment).not.toHaveAttribute('data-readonly');
}
for (let literal of [...input.children].filter(child => child.getAttribute('data-type') === 'literal')) {
expect(literal).not.toHaveAttribute('data-readonly');
}
});
it('should support readonly state', () => {
let {getByRole, getAllByRole} = render(
<DateField isReadOnly>
<Label>Birth date</Label>
<DateInput>
{segment => <DateSegment segment={segment} />}
</DateInput>
</DateField>
);
let group = getByRole('group');
expect(group).toHaveAttribute('data-readonly');
expect(group).not.toHaveAttribute('data-disabled');
expect(group).not.toHaveClass('disabled');
for (let segment of getAllByRole('spinbutton')) {
expect(segment).toHaveAttribute('data-readonly');
expect(segment).not.toHaveAttribute('data-disabled');
}
for (let literal of [...group.children].filter(child => child.getAttribute('data-type') === 'literal')) {
expect(literal).toHaveAttribute('data-readonly');
expect(literal).not.toHaveAttribute('data-disabled');
}
});
it('should support readonly with disabled state', () => {
let {getByRole, getAllByRole} = render(
<DateField isReadOnly isDisabled>
<Label>Birth date</Label>
<DateInput>
{segment => <DateSegment segment={segment} />}
</DateInput>
</DateField>
);
let group = getByRole('group');
expect(group).toHaveAttribute('data-readonly');
expect(group).toHaveAttribute('data-disabled');
expect(group).toHaveClass('disabled');
for (let segment of getAllByRole('spinbutton')) {
expect(segment).toHaveAttribute('data-readonly');
expect(segment).toHaveAttribute('data-disabled');
}
for (let literal of [...group.children].filter(child => child.getAttribute('data-type') === 'literal')) {
expect(literal).toHaveAttribute('data-readonly');
expect(segment).toHaveAttribute('data-disabled');
}
});
it('should support disabled state', () => {
let {getByRole, getAllByRole} = render(
<DateField isDisabled>
<Label>Birth date</Label>
<DateInput className={({isDisabled}) => isDisabled ? 'disabled' : ''}>
{segment => <DateSegment segment={segment} />}
</DateInput>
</DateField>
);
let group = getByRole('group');
expect(group).not.toHaveAttribute('data-readonly');
expect(group).toHaveAttribute('data-disabled');
expect(group).toHaveClass('disabled');
for (let segment of getAllByRole('spinbutton')) {
expect(segment).not.toHaveAttribute('data-readonly');
expect(segment).toHaveAttribute('data-disabled');
}
for (let literal of [...group.children].filter(child => child.getAttribute('data-type') === 'literal')) {
expect(literal).not.toHaveAttribute('data-readonly');
expect(segment).toHaveAttribute('data-disabled');
}
}); |
Found During Testing
When
isReadonly
is set, all segments should be non-editable.For RAC components, this ensures that when
isReadonly
is applied toDateField
orTimeField
, the non-literalDateSegments
haveisReadonly=true
andisEditable=false
✅ Pull Request Checklist:
📝 Test Instructions:
🧢 Your Project: