feat: add Loading component and loading states across components - #254
seanrcollings wants to merge 9 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Four unresolved moderate issues affect loading labels, accessibility, and FileInput loading behavior.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds an ambient Loading provider and hook, skeleton loading states across components, and updated Storybook/playground examples.
Changes:
- Adds loading context, translations, and component integrations.
- Updates fields, inputs, dropdowns, tables, buttons, and feedback components.
- Adds stories, snapshots, playground content, and changeset metadata.
File summaries
| File | Summary |
|---|---|
playground/src/tabs/LoadingStates.tsx |
Adds loading demonstrations. |
playground/src/tabs/Loading.tsx |
Removes superseded loading tab. |
playground/src/tabs/Fields.tsx |
Adds ambient loading example. |
playground/src/Playground.tsx |
Registers Loading States tab. |
packages/atomic-elements/src/types/fields.ts |
Adds loading field props. |
packages/atomic-elements/src/types/common.ts |
Updates loading definitions. |
packages/atomic-elements/src/i18n/en-US.ts |
Adds loading translation. |
packages/atomic-elements/src/components/Internal/BaseButton.tsx |
Integrates ambient loading. |
packages/atomic-elements/src/components/Inputs/ToggleSwitch/ToggleSwitch.styles.ts |
Adds loading styles. |
packages/atomic-elements/src/components/Inputs/ToggleSwitch/ToggleSwitch.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Inputs/ToggleSwitch/ToggleSwitch.component.tsx |
Adds toggle loading state. |
packages/atomic-elements/src/components/Inputs/TextInput/TextInput.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Inputs/TextInput/__snapshots__/TextInput.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Inputs/TextAreaInput/TextAreaInput.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Inputs/TextAreaInput/__snapshots__/TextAreaInput.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Inputs/SearchInput/SearchInput.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Inputs/SearchInput/__snapshots__/SearchInput.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Inputs/RadioGroup/RadioGroup.styles.ts |
Adds loading styles. |
packages/atomic-elements/src/components/Inputs/RadioGroup/RadioGroup.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Inputs/RadioGroup/RadioGroup.component.tsx |
Adds radio loading state. |
packages/atomic-elements/src/components/Inputs/RadioGroup/__snapshots__/RadioGroup.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Inputs/NumberInput/NumberInput.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Inputs/FileInput/FileInput.styles.ts |
Adds loading styles. |
packages/atomic-elements/src/components/Inputs/FileInput/FileInput.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Inputs/FileInput/FileInput.component.tsx |
Adds file input loading state. |
packages/atomic-elements/src/components/Inputs/DateAndTimes/DateInput/__snapshots__/DateInput.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Inputs/Checkbox/Checkbox.styles.ts |
Adds loading styles. |
packages/atomic-elements/src/components/Inputs/Checkbox/Checkbox.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Inputs/Checkbox/Checkbox.component.tsx |
Adds checkbox loading state. |
packages/atomic-elements/src/components/Inputs/Checkbox/__snapshots__/CheckBox.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/index.ts |
Exports loading APIs. |
packages/atomic-elements/src/components/Fields/TextField/TextField.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Fields/TextField/TextField.component.tsx |
Adds text field loading support. |
packages/atomic-elements/src/components/Fields/SelectField/__snapshots__/SelectField.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Fields/SearchField/SearchField.component.tsx |
Propagates loading context. |
packages/atomic-elements/src/components/Fields/NumberField/NumberField.component.tsx |
Propagates loading context. |
packages/atomic-elements/src/components/Fields/MultiSelectField/__snapshots__/MultiSelectField.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Fields/DateField/__snapshots__/DateField.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Fields/ComboInput/ComboInput.types.ts |
Adds loading types. |
packages/atomic-elements/src/components/Fields/ComboInput/ComboInput.styles.ts |
Adds loading styles. |
packages/atomic-elements/src/components/Fields/ComboInput/ComboInput.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Fields/ComboInput/ComboInput.component.tsx |
Adds combo input loading state. |
packages/atomic-elements/src/components/Fields/ComboBoxField/ComboBoxField.types.ts |
Adds loading types. |
packages/atomic-elements/src/components/Fields/ComboBoxField/ComboBoxField.component.tsx |
Propagates loading context. |
packages/atomic-elements/src/components/Fields/ChipGroupField/__snapshots__/ChipGroupField.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Fields/Atoms/TextArea/TextArea.styles.ts |
Adds loading styles. |
packages/atomic-elements/src/components/Fields/Atoms/TextArea/TextArea.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Fields/Atoms/TextArea/TextArea.component.tsx |
Adds textarea loading state. |
packages/atomic-elements/src/components/Fields/Atoms/Message/Message.component.tsx |
Adjusts DOM prop forwarding. |
packages/atomic-elements/src/components/Fields/Atoms/Label/Label.component.tsx |
Adjusts label prop forwarding. |
packages/atomic-elements/src/components/Fields/Atoms/Input/Input.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Fields/Atoms/Input/Input.component.tsx |
Adds input loading state. |
packages/atomic-elements/src/components/Fields/Atoms/ErrorMessage/ErrorMessage.component.tsx |
Adjusts DOM prop forwarding. |
packages/atomic-elements/src/components/Feedback/LoadingStatus/LoadingStatus.component.tsx |
Integrates ambient loading. |
packages/atomic-elements/src/components/Feedback/Loading/Loading.stories.tsx |
Adds provider stories. |
packages/atomic-elements/src/components/Feedback/Loading/Loading.context.ts |
Adds loading context and hook. |
packages/atomic-elements/src/components/Feedback/Loading/Loading.component.tsx |
Adds loading provider. |
packages/atomic-elements/src/components/Feedback/Loading/index.tsx |
Exports loading components. |
packages/atomic-elements/src/components/Dropdowns/Select/__snapshots__/Select.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Dropdowns/MultiSelect/MultiSelect.styles.ts |
Adds loading styles. |
packages/atomic-elements/src/components/Dropdowns/MultiSelect/MultiSelect.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Dropdowns/MultiSelect/MultiSelect.component.tsx |
Adds multiselect loading state. |
packages/atomic-elements/src/components/Dropdowns/MultiSelect/__snapshots__/MultiSelect.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Dropdowns/ListBox/__snapshots__/ListBox.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Dropdowns/CustomSelect/CustomSelect.styles.ts |
Adds loading styles. |
packages/atomic-elements/src/components/Dropdowns/CustomSelect/CustomSelect.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Dropdowns/CustomSelect/CustomSelect.component.tsx |
Adds select loading state. |
packages/atomic-elements/src/components/Dropdowns/CustomSelect/__snapshots__/CustomSelect.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Dropdowns/Combobox/Combobox.styles.ts |
Adds loading styles. |
packages/atomic-elements/src/components/Dropdowns/Combobox/Combobox.stories.tsx |
Adds loading story. |
packages/atomic-elements/src/components/Dropdowns/Combobox/ComboBox.component.tsx |
Adds combobox loading state. |
packages/atomic-elements/src/components/Dropdowns/Combobox/__snapshots__/Combobox.spec.tsx.snap |
Updates snapshots. |
packages/atomic-elements/src/components/Content/Table/components/TableBody.tsx |
Integrates ambient table loading. |
packages/atomic-elements/src/components/Chips/ChipGroup/__snapshots__/ChipGroup.spec.tsx.snap |
Updates snapshots. |
.storybook/utils/helpers.tsx |
Adds loading Storybook controls. |
.changeset/thick-tires-yawn.md |
Documents package changes. |
Review details
Suppressed comments (2)
packages/atomic-elements/src/components/Feedback/Loading/Loading.component.tsx:37
- When callers omit
loadingLabel, the provider's live status announces an empty string even though the component has a translated fallback available. Use the resolved context value here so the ambient provider is accessible with its default label as well.
<VisuallyHidden role="status" aria-live="polite">
{isLoading ? loadingLabel : ""}
</VisuallyHidden>
packages/atomic-elements/src/components/Inputs/FileInput/FileInput.component.tsx:86
- When
isLoadingis true, this branch replaces the entire field contents with only the skeleton, so aFileInputlabel (and its accessible field context) disappears. This differs from the other loading field components and leaves the loading control without its normal label; keep the label/field wrapper rendered while replacing only the interactive input with the skeleton.
- Files reviewed: 78/78 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
The review found a critical label rendering regression and unresolved loading behavior issues.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (4)
packages/atomic-elements/src/components/Dropdowns/Combobox/ComboBox.component.tsx:60
- The loading branch omits
renderPropseven though the normal branch applies it. This drops theaje-combobox, variant, size, custom class, and style output while loading, so the skeleton is not styled consistently with the same component when it is not loading.
<StyledComboBoxField {...props} ref={ref}>
packages/atomic-elements/src/components/Feedback/Loading/Loading.component.tsx:23
- The provider drops the caller's
loadingLabelwhen constructing the context value and always publishest("loading"). As a result, descendants using the ambient provider cannot receive a custom loading label even thoughLoadingProviderPropsexposes it; passloadingLabel ?? t("loading")into the context value (and keep the dependency aligned).
const value = useMemo<LoadingProps>(
() => ({ isLoading, loadingLabel: t("loading") }),
[isLoading, loadingLabel]
packages/atomic-elements/src/components/Feedback/Loading/Loading.component.tsx:36
- When no
loadingLabelis passed, the provider's visually hidden status announces an empty string even though the component defines a translated default. Use the resolved label from the context value (or the same fallback) here so the ambient loading state is announced.
<VisuallyHidden role="status" aria-live="polite">
{isLoading ? loadingLabel : ""}
packages/atomic-elements/src/components/Inputs/FileInput/FileInput.component.tsx:86
- The loading branch replaces the entire
FileInputcontents with only the skeleton, so the suppliedlabel, required marker, message, and error are dropped (the Loading story passeslabel="Upload"). This makes the loading state lose the field's visible context and differs from the other field loading implementations that retain their label wrapper.
- Files reviewed: 78/78 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Two moderate issues remain in the loading provider label handling and FileInput loading structure.
Review details
Suppressed comments (2)
packages/atomic-elements/src/components/Feedback/Loading/Loading.component.tsx:24
- The provider ignores the caller's
loadingLabelwhen building the context and always publishes the translated default. As a result, a custom label passed to<Loading loadingLabel="...">is announced by the provider but is not used by descendant skeletons/buttons, and when no label is supplied the provider's live region is empty because line 36 reads the un-fallbacked prop. PublishloadingLabel ?? t("loading")in both places (or derive the effective label once) so the ambient and live-region behavior agree.
const value = useMemo<LoadingProps>(
() => ({ isLoading, loadingLabel: t("loading") }),
[isLoading, loadingLabel]
);
packages/atomic-elements/src/components/Inputs/FileInput/FileInput.component.tsx:85
- When loading, this early return removes the file input's label, message, error, and other field DOM props; a labeled
<FileInput isLoading />therefore renders only an unlabeled skeleton, unlike the normal branch and the other loading field components. Keep the field wrapper/label and status content in the loading branch, or render the skeleton through the sameFileInputButton/field structure while replacing only the interactive control.
- Files reviewed: 77/77 changed files
- Comments generated: 0 new
- Review effort level: Lite
Summary
<Loading>ambient provider component anduseLoading()hook, so a group of fields can be marked as loading from one place instead of threadingisLoadingthrough every child.isLoading/loadingLabelsupport (skeleton loading states) toInput,TextArea,ComboInput,TextField,NumberField/NumberInput,SearchField/SearchInput,TextInput,TextAreaInput,CheckBox,ToggleSwitch,RadioGroup,FileInput,CustomSelect,MultiSelect,ComboBox,Table, and wiresButton/IconButton/LoadingStatusup to the same ambientuseLoading()context.Loadingstories file with simple examples and a more complex example form.Loadingtab).Screenshots
Test plan
npm run build --workspace @atomicjolt/atomic-elementspassesFeedback/Loadingstories in a browser