@jobber/components-native 0.101.5 → 0.101.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/docs/ActionItem/ActionItem.md +65 -0
- package/dist/docs/ActionItemGroup/ActionItemGroup.md +33 -0
- package/dist/docs/ActionLabel/ActionLabel.md +43 -0
- package/dist/docs/ActivityIndicator/ActivityIndicator.md +116 -0
- package/dist/docs/Animation/Animation.md +71 -0
- package/dist/docs/AtlantisThemeContext/AtlantisThemeContext.md +256 -0
- package/dist/docs/AutoLink/AutoLink.md +47 -0
- package/dist/docs/Banner/Banner.md +390 -0
- package/dist/docs/Borders/Borders.md +45 -0
- package/dist/docs/BottomSheet/BottomSheet.md +67 -0
- package/dist/docs/Button/Button.md +918 -0
- package/dist/docs/ButtonGroup/ButtonGroup.md +89 -0
- package/dist/docs/Card/Card.md +270 -0
- package/dist/docs/Checkbox/Checkbox.md +69 -0
- package/dist/docs/Chip/Chip.md +371 -0
- package/dist/docs/Colors/Colors.md +217 -0
- package/dist/docs/Content/Content.md +67 -0
- package/dist/docs/ContentOverlay/ContentOverlay.md +64 -0
- package/dist/docs/Disclosure/Disclosure.md +161 -0
- package/dist/docs/Divider/Divider.md +84 -0
- package/dist/docs/Elevations/Elevations.md +76 -0
- package/dist/docs/EmptyState/EmptyState.md +72 -0
- package/dist/docs/Flex/Flex.md +37 -0
- package/dist/docs/Form/Form.md +126 -0
- package/dist/docs/FormField/FormField.md +57 -0
- package/dist/docs/FormatFile/FormatFile.md +56 -0
- package/dist/docs/Glimmer/Glimmer.md +143 -0
- package/dist/docs/Heading/Heading.md +132 -0
- package/dist/docs/Icon/Icon.md +585 -0
- package/dist/docs/IconButton/IconButton.md +25 -0
- package/dist/docs/InputCurrency/InputCurrency.md +61 -0
- package/dist/docs/InputDate/InputDate.md +133 -0
- package/dist/docs/InputEmail/InputEmail.md +69 -0
- package/dist/docs/InputFieldWrapper/InputFieldWrapper.md +70 -0
- package/dist/docs/InputNumber/InputNumber.md +72 -0
- package/dist/docs/InputPassword/InputPassword.md +61 -0
- package/dist/docs/InputPressable/InputPressable.md +64 -0
- package/dist/docs/InputSearch/InputSearch.md +49 -0
- package/dist/docs/InputText/InputText.md +324 -0
- package/dist/docs/InputTime/InputTime.md +54 -0
- package/dist/docs/Opacity/Opacity.md +12 -0
- package/dist/docs/ProgressBar/ProgressBar.md +39 -0
- package/dist/docs/Radii/Radii.md +23 -0
- package/dist/docs/ResponsiveBreakpoint/ResponsiveBreakpoint.md +74 -0
- package/dist/docs/Select/Select.md +213 -0
- package/dist/docs/Spacing/Spacing.md +103 -0
- package/dist/docs/StatusLabel/StatusLabel.md +119 -0
- package/dist/docs/Switch/Switch.md +54 -0
- package/dist/docs/Text/Text.md +368 -0
- package/dist/docs/TextList/TextList.md +29 -0
- package/dist/docs/ThumbnailList/ThumbnailList.md +16 -0
- package/dist/docs/Toast/Toast.md +71 -0
- package/dist/docs/Typography/Typography.md +170 -0
- package/dist/docs/choosing-components/choosing-components.md +76 -0
- package/dist/docs/customizing-components/customizing-components.md +167 -0
- package/dist/docs/disabled-states/disabled-states.md +86 -0
- package/dist/docs/empty-states/empty-states.md +126 -0
- package/dist/docs/errors/errors.md +114 -0
- package/dist/docs/index.md +64 -0
- package/dist/docs/interaction/interaction.md +109 -0
- package/dist/docs/page-layouts/page-layouts.md +323 -0
- package/dist/docs/scaffolding/scaffolding.md +109 -0
- package/dist/docs/settings/settings.md +58 -0
- package/dist/docs/usage-guidelines/usage-guidelines.md +177 -0
- package/dist/package.json +8 -4
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +8 -4
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Atlantis Component Selection
|
|
2
|
+
|
|
3
|
+
When implementing UI, default to importing Atlantis components before writing
|
|
4
|
+
any JSX structure.
|
|
5
|
+
|
|
6
|
+
Before writing any UI code, determine whether Atlantis already provides the
|
|
7
|
+
needed component, pattern, or primitive.
|
|
8
|
+
|
|
9
|
+
## Required Decision Process
|
|
10
|
+
|
|
11
|
+
For every UI request, follow this process:
|
|
12
|
+
|
|
13
|
+
1. Identify the UI elements being requested
|
|
14
|
+
2. Map each element to an Atlantis component or Atlantis typography/layout
|
|
15
|
+
primitive
|
|
16
|
+
3. Prefer Atlantis defaults over custom composition
|
|
17
|
+
4. Only introduce custom markup/styling for product-specific layout or missing
|
|
18
|
+
behavior
|
|
19
|
+
5. If Atlantis does not cover something, implement the smallest possible custom
|
|
20
|
+
layer
|
|
21
|
+
|
|
22
|
+
## Atlantis-First Rule
|
|
23
|
+
|
|
24
|
+
Always assume Atlantis has the right starting point.
|
|
25
|
+
|
|
26
|
+
Check Atlantis first for:
|
|
27
|
+
|
|
28
|
+
* page structure
|
|
29
|
+
* headings and text
|
|
30
|
+
* actions
|
|
31
|
+
* forms
|
|
32
|
+
* overlays
|
|
33
|
+
* menus
|
|
34
|
+
* banners and notices
|
|
35
|
+
* empty/error/loading states
|
|
36
|
+
* icons
|
|
37
|
+
* containers and surfaces
|
|
38
|
+
|
|
39
|
+
Do not jump straight to raw divs plus custom styling when Atlantis components
|
|
40
|
+
could solve the problem.
|
|
41
|
+
|
|
42
|
+
## Output Expectations
|
|
43
|
+
|
|
44
|
+
When generating UI:
|
|
45
|
+
|
|
46
|
+
* choose Atlantis components first
|
|
47
|
+
* compose from Atlantis primitives
|
|
48
|
+
* keep wrappers minimal
|
|
49
|
+
* avoid custom components unless they add product-specific behavior
|
|
50
|
+
|
|
51
|
+
## Forbidden Behavior
|
|
52
|
+
|
|
53
|
+
Do not:
|
|
54
|
+
|
|
55
|
+
* build a new Button when Atlantis has one
|
|
56
|
+
* build custom text styles instead of using Heading or Text
|
|
57
|
+
* build a custom modal, tooltip, menu, or input if Atlantis provides one
|
|
58
|
+
* style raw HTML to imitate Atlantis
|
|
59
|
+
|
|
60
|
+
## If No Atlantis Match Exists
|
|
61
|
+
|
|
62
|
+
If Atlantis truly does not provide a direct match:
|
|
63
|
+
|
|
64
|
+
* use the closest Atlantis primitives possible
|
|
65
|
+
* keep the custom piece small
|
|
66
|
+
* use Atlantis tokens
|
|
67
|
+
* avoid inventing a new visual pattern
|
|
68
|
+
* state the assumption in code comments only if necessary
|
|
69
|
+
|
|
70
|
+
## Final Check Before Output
|
|
71
|
+
|
|
72
|
+
Before finalizing code, verify:
|
|
73
|
+
|
|
74
|
+
* Could any custom element be replaced with an Atlantis component?
|
|
75
|
+
* Could any text element be replaced with Heading or Text?
|
|
76
|
+
* Could any visual styling be removed in favor of Atlantis defaults?
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Customizing components
|
|
2
|
+
|
|
3
|
+
## Balancing simplicity, flexibility, and consistency
|
|
4
|
+
|
|
5
|
+
Atlantis is designed to make building consistent, accessible, and visually
|
|
6
|
+
appealing user interfaces as effortless as possible for you.
|
|
7
|
+
|
|
8
|
+
We strive to speed up building the most common use cases "out of the box" with
|
|
9
|
+
thoughtful defaults that create consistency for users. When unique scenarios
|
|
10
|
+
arise that may require customization, we provide flexible mechanisms to extend
|
|
11
|
+
or modify our components without compromising the integrity of their most common
|
|
12
|
+
use cases.
|
|
13
|
+
|
|
14
|
+
We recommend using the default implementations wherever possible to benefit
|
|
15
|
+
from:
|
|
16
|
+
|
|
17
|
+
* consistency
|
|
18
|
+
* improvements from the design system "for free"
|
|
19
|
+
* built-in accessibility
|
|
20
|
+
|
|
21
|
+
If you choose to customize components, you assume responsibility for these
|
|
22
|
+
concerns and any issues that may arise in future versions.
|
|
23
|
+
|
|
24
|
+
## Compound components
|
|
25
|
+
|
|
26
|
+
Some components expose their foundational building blocks. This usually includes
|
|
27
|
+
subcomponents and hooks for providing styles, state, and additional logic.
|
|
28
|
+
|
|
29
|
+
These components provide greater flexibility, giving you much more control over
|
|
30
|
+
their appearance and behaviour.
|
|
31
|
+
|
|
32
|
+
### Example: [Button](../Button/Button.md)
|
|
33
|
+
|
|
34
|
+
The `Button` component offers a very simple API allowing you to specify a label,
|
|
35
|
+
icon, and icon position. However, because it doesn't accept children, it's very
|
|
36
|
+
inflexible.
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
<Button label="Home" icon="home" iconOnRight />
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
For greater control, `Button` is also available as a compound component and has
|
|
43
|
+
exposed `Button.Label` and `Button.Icon` as subcomponents. This allows complete
|
|
44
|
+
customization of the button's underlying content.
|
|
45
|
+
|
|
46
|
+
Using the provided subcomponents, it's possible to build something more complex
|
|
47
|
+
like this:
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
function Example() {
|
|
51
|
+
const [created, setCreated] = useState(false);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Button
|
|
55
|
+
onClick={() => setCreated(!created)}
|
|
56
|
+
variation={created ? "destructive" : "work"}
|
|
57
|
+
>
|
|
58
|
+
{created ? <Avatar initials="AB" /> : <Button.Icon name="person" />}
|
|
59
|
+
<Button.Label>{created ? "Delete user" : "Create user"}</Button.Label>
|
|
60
|
+
</Button>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`Button` also exposes a few hooks that can be used within your own components:
|
|
66
|
+
|
|
67
|
+
* `useButtonStyles`: Returns a map of css classes that `Button` uses internally.
|
|
68
|
+
Consumers might use this to make something else look like a `Button`.
|
|
69
|
+
* `useButtonContext`: Returns internal context that the `Button` shares with its
|
|
70
|
+
subcomponents. Consumers might use Button's context within a custom child
|
|
71
|
+
component, allowing that child to adapt to the `size` prop for example.
|
|
72
|
+
|
|
73
|
+
## Named `customRender____` props
|
|
74
|
+
|
|
75
|
+
Some of our components use render props following the `customRender____` naming
|
|
76
|
+
convention.
|
|
77
|
+
|
|
78
|
+
This allows you to both:
|
|
79
|
+
|
|
80
|
+
* inject your own UI logic
|
|
81
|
+
* retain the default behaviors and functionality of the component
|
|
82
|
+
|
|
83
|
+
[Reference implementation](https://github.com/GetJobber/atlantis/blob/304e776cf7fc1b9683cecbb1d7a0d8dbebdb60bb/packages/components/src/List/List.tsx#L25C3-L25C60)
|
|
84
|
+
|
|
85
|
+
### Example: [List](../components/List) customRenderItem
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
const renderProductItem = item => (
|
|
89
|
+
<Flex template={["shrink", "grow"]} align="start">
|
|
90
|
+
<Text>{item.price}</Text>
|
|
91
|
+
<Heading level={4}>{item.name}</Heading>
|
|
92
|
+
</Flex>
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
export const CustomRenderExample = () => (
|
|
96
|
+
<List items={items} customRenderItem={renderProductItem} />
|
|
97
|
+
);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Slot props with ReactNode
|
|
101
|
+
|
|
102
|
+
Extending prop types to allow a `ReactNode` to be inserted is useful for simpler
|
|
103
|
+
cases where your:
|
|
104
|
+
|
|
105
|
+
* customization does not depend on internal state
|
|
106
|
+
* design is relatively simple
|
|
107
|
+
|
|
108
|
+
[Reference implementation](https://github.com/GetJobber/atlantis/blob/master/packages/components/src/Tabs/Tabs.tsx#L119C3-L119C38)
|
|
109
|
+
|
|
110
|
+
### Example: [Tab](../components/Tabs) label
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
<Tab label={<MyCustomLabel />} />
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Customizing the `label` doesn’t require exposing or interacting with the `Tab`’s
|
|
117
|
+
internal state (e.g., active state styling).
|
|
118
|
+
|
|
119
|
+
## UNSAFE\_ props
|
|
120
|
+
|
|
121
|
+
> **WARNING:** These properties are prefixed `UNSAFE_` for a reason! Their usage is **at your
|
|
122
|
+
> own risk** and should be considered a **last resort**. Atlantis updates may
|
|
123
|
+
> break these usages.
|
|
124
|
+
|
|
125
|
+
`UNSAFE_` props are used to allow for advanced styling customization of:
|
|
126
|
+
|
|
127
|
+
* a component's container
|
|
128
|
+
* in some cases, a component's sub-components
|
|
129
|
+
|
|
130
|
+
If you are considering using an `UNSAFE_` prop, we encourage you to
|
|
131
|
+
[talk to us](https://getjobber.slack.com/archives/C03BJHV3PMG) to look for safer
|
|
132
|
+
ways to meet your needs.
|
|
133
|
+
|
|
134
|
+
[Reference implementation](https://github.com/GetJobber/atlantis/blob/304e776cf7fc1b9683cecbb1d7a0d8dbebdb60bb/packages/components/src/Popover/Popover.tsx#L36-L56)
|
|
135
|
+
|
|
136
|
+
### Example: `UNSAFE_className`
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
<Component UNSAFE_className={{ container: styles.customClass }} />
|
|
140
|
+
|
|
141
|
+
.customClass {
|
|
142
|
+
background-color: var(--color-surface--background);
|
|
143
|
+
padding-right: var(--space-larger);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
<Component UNSAFE_className={{ container: "custom-container-class" }} />
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Example: `UNSAFE_style`
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
<Component
|
|
155
|
+
UNSAFE_style={{
|
|
156
|
+
container: { backgroundColor: "var(--color-surface--background)" },
|
|
157
|
+
dismissArrow: { paddingRight: "var(--space-larger)" },
|
|
158
|
+
}}
|
|
159
|
+
/>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Note:** Inspiration for this approach was taken from:
|
|
163
|
+
|
|
164
|
+
* React Spectrum's
|
|
165
|
+
[UNSAFE\_ escape hatches](https://react-spectrum.adobe.com/react-spectrum/styling.html#escape-hatches)
|
|
166
|
+
* Gestalt's
|
|
167
|
+
[dangerouslySet\*\*\_\*\* pattern](https://gestalt.pinterest.systems/get_started/developers/hacking_gestalt#Box's-dangerouslySetInlineStyle)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Disabled states
|
|
2
|
+
|
|
3
|
+
| **Platform** | **Status** |
|
|
4
|
+
| :----------- | :--------- |
|
|
5
|
+
| Web Mobile | Ready |
|
|
6
|
+
|
|
7
|
+
This pattern involves how we disable, show, or hide actions based on different
|
|
8
|
+
criteria. It becomes a balance in explaining the interface and not overwhelming
|
|
9
|
+
users with choice. Below are a few of the common examples and accompanying
|
|
10
|
+
guidelines for handling those situations.
|
|
11
|
+
|
|
12
|
+
## Goal
|
|
13
|
+
|
|
14
|
+
Avoid placing the user in a frustrating state where actions are unavailable and
|
|
15
|
+
they do not know how to enable.
|
|
16
|
+
|
|
17
|
+
## Use when…
|
|
18
|
+
|
|
19
|
+
There's absolutely no other way to avoid a disabled state. This should be a last
|
|
20
|
+
resort. This flowchart can help you find alternatives:
|
|
21
|
+
|
|
22
|
+
## Solution
|
|
23
|
+
|
|
24
|
+
### Avoid disabled states
|
|
25
|
+
|
|
26
|
+
Your first goal should be to avoid disabled states entirely. If there is a
|
|
27
|
+
condition required for the user to take an action, present the opportunity to
|
|
28
|
+
set the required condition before the user is blocked by a disabled state. An
|
|
29
|
+
example of this is on our “work objects” which all require a client to be saved.
|
|
30
|
+
If the user makes it to the bottom of the form and has not added a client, the
|
|
31
|
+
primary CTA is “Select Client“.
|
|
32
|
+
|
|
33
|
+
#### Permissions-related unavailability
|
|
34
|
+
|
|
35
|
+
When functionality or a feature isn't available because of a user's permissions,
|
|
36
|
+
hide the action altogether.
|
|
37
|
+
|
|
38
|
+
#### Account-tier-related unavailability
|
|
39
|
+
|
|
40
|
+
If functionality is unavailable because of a user’s subscription tier, but we
|
|
41
|
+
want to introduce the functionality to encourage them to upgrade, use an inline
|
|
42
|
+
element near where the unavailable UI would exist, or a
|
|
43
|
+
`Button variation="learning"` in place of the UI to nudge the user to learn
|
|
44
|
+
more.
|
|
45
|
+
|
|
46
|
+
### Why
|
|
47
|
+
|
|
48
|
+
Avoiding disabled states is an accessibility best practice and also generally
|
|
49
|
+
helpful from a usability perspective. The more time a user spends trying to
|
|
50
|
+
understand why they can’t take an action, the less time they spend getting sh\*t
|
|
51
|
+
done.
|
|
52
|
+
|
|
53
|
+
Disabling elements is often the easiest path for a development team to manage
|
|
54
|
+
conditional states of an interface to design and build, but results in a
|
|
55
|
+
less-friendly interface for the user.
|
|
56
|
+
|
|
57
|
+
### Implementation
|
|
58
|
+
|
|
59
|
+
While you should avoid disabled states, many Atlantis components do offer a
|
|
60
|
+
`disabled` boolean property for absolutely necessary cases. If you use the
|
|
61
|
+
disabled state, you must ensure that the user can understand *why* the element
|
|
62
|
+
is disabled.
|
|
63
|
+
|
|
64
|
+
### Web
|
|
65
|
+
|
|
66
|
+
A [Tooltip](../components/Tooltip) may help explain to the user why they
|
|
67
|
+
can’t select an element. Make sure the Tooltip can be triggered both by
|
|
68
|
+
focus and hover.
|
|
69
|
+
|
|
70
|
+
### Mobile
|
|
71
|
+
|
|
72
|
+
[Text](../Text/Text.md) (level="supportingText") is more helpful for users
|
|
73
|
+
in the mobile app as it does not require an additional interaction to
|
|
74
|
+
uncover. If an input element (such as a Select or InputText) has “assistive
|
|
75
|
+
text” built in, do not use the assistive text in a disabled state, but
|
|
76
|
+
provide the supporting Text as a separate element.
|
|
77
|
+
|
|
78
|
+
## Related
|
|
79
|
+
|
|
80
|
+
* [Interaction](../interaction/interaction.md)
|
|
81
|
+
* [Empty states](../empty-states/empty-states.md)
|
|
82
|
+
|
|
83
|
+
## Principles
|
|
84
|
+
|
|
85
|
+
* [Visibility of system status](https://www.nngroup.com/articles/visibility-system-status/)
|
|
86
|
+
* [Recognition over recall](https://www.nngroup.com/articles/recognition-and-recall/)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Empty states
|
|
2
|
+
|
|
3
|
+
| **Platform** | **Status** |
|
|
4
|
+
| :----------- | :--------- |
|
|
5
|
+
| Web Mobile | Ready |
|
|
6
|
+
|
|
7
|
+
## Goal
|
|
8
|
+
|
|
9
|
+
Ensure the user does not hit a dead end when there is no content to display.
|
|
10
|
+
|
|
11
|
+
## Use when...
|
|
12
|
+
|
|
13
|
+
Use when there *could* be content in a view, but there is none. Possible reasons
|
|
14
|
+
for the “emptiness” may include, but are not limited to…
|
|
15
|
+
|
|
16
|
+
* A notifications panel when the user hasn't received any notifications
|
|
17
|
+
* A list of user-generated content before user has created any content (for
|
|
18
|
+
example, a list of clients when the user doesn’t yet have any clients)
|
|
19
|
+
* Dashboards or other data-centric views when the user has not generated any
|
|
20
|
+
data (ie Home)
|
|
21
|
+
* Search results with no match
|
|
22
|
+
* An error has resulted in the user not being able to access content they
|
|
23
|
+
otherwise could
|
|
24
|
+
|
|
25
|
+
## Solution
|
|
26
|
+
|
|
27
|
+
A successful empty state should:
|
|
28
|
+
|
|
29
|
+
* communicate system status
|
|
30
|
+
* increase learnability of the system
|
|
31
|
+
* deliver direct pathways for key tasks
|
|
32
|
+
|
|
33
|
+
[Designing Empty States in Complex Applications: 3 Guidelines](https://www.nngroup.com/articles/empty-state-interface-design/#:~:text=Empty%20states%20that%20are%20intentionally,getting%20started%20with%20key%20tasks)
|
|
34
|
+
|
|
35
|
+
#### When *not* to add a CTA
|
|
36
|
+
|
|
37
|
+
You might not use a direct CTA in the empty state if:
|
|
38
|
+
|
|
39
|
+
* The action to populate the empty state has dependencies on another action
|
|
40
|
+
being taken
|
|
41
|
+
* Example: Quotes must be approved by clients before they appear in a list of
|
|
42
|
+
"approved quotes"
|
|
43
|
+
* Example: A payment requires creation and delivery of an invoice, and the
|
|
44
|
+
client to make a payment, before it exists
|
|
45
|
+
|
|
46
|
+
### In lists
|
|
47
|
+
|
|
48
|
+
Adjust your context and actions if the user has no content because of a search
|
|
49
|
+
or filter, vs when they have no content at all.
|
|
50
|
+
|
|
51
|
+
### Error states
|
|
52
|
+
|
|
53
|
+
A full-screen "empty" error state can help the user make sense of what's going
|
|
54
|
+
on, and how to get back on track. If an entire view goes blank due to an error,
|
|
55
|
+
a single Banner can look out of place.
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
<Box direction="column" alignItems="center" gap="base" width="100%">
|
|
59
|
+
<Icon size="large" name="alert" color="critical" />
|
|
60
|
+
<Heading level={4}>Something went wrong</Heading>
|
|
61
|
+
<Text>Couldn't load content. Refresh to try again.</Text>
|
|
62
|
+
<Button label="Refresh" />
|
|
63
|
+
</Box>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### When the user can't add content
|
|
67
|
+
|
|
68
|
+
When a card is empty, and there is no way for the user to add content, you
|
|
69
|
+
should still show some form of empty state, but without a CTA.
|
|
70
|
+
|
|
71
|
+
Do not hide the card, as this state-based hiding and showing may not be
|
|
72
|
+
intuitive for the user. For example, see the ”Payments” card here, where the
|
|
73
|
+
user needs to create an invoice and interact with their client before they can
|
|
74
|
+
create a payment against a job.
|
|
75
|
+
|
|
76
|
+
## Why
|
|
77
|
+
|
|
78
|
+
By considering and accounting for these often “un-happy” paths in the user’s
|
|
79
|
+
journey, we can allow the user to learn how to use Jobber more effectively,
|
|
80
|
+
guide them out of troublesome scenarios, and ensure that they never feel like
|
|
81
|
+
they’ve hit a dead-end in the product.
|
|
82
|
+
|
|
83
|
+
## Implementation
|
|
84
|
+
|
|
85
|
+
### Web
|
|
86
|
+
|
|
87
|
+
There's no component but these are some common patterns:
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
<Box direction="column" alignItems="center" gap="base" width="100%">
|
|
91
|
+
<Icon size="large" name="alert" />
|
|
92
|
+
<Heading level={4}>No results found</Heading>
|
|
93
|
+
<Text>Try adjusting your search criteria or clearing filters</Text>
|
|
94
|
+
<Button variation="subtle" label="Clear Filters" />
|
|
95
|
+
</Box>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Mobile
|
|
99
|
+
|
|
100
|
+
[EmptyState](../EmptyState/EmptyState.md) gives you the boilerplate
|
|
101
|
+
`Icon` + `Heading` + `Text` + `Button` out of the box but you can also compose it
|
|
102
|
+
similar to the web implementation if more flexibility is needed.
|
|
103
|
+
|
|
104
|
+
## Not obvious details
|
|
105
|
+
|
|
106
|
+
In some cases, illustrations may be useful in an empty state to bring some
|
|
107
|
+
personality to the scenario. If this fits your use case, work with the design
|
|
108
|
+
team to find or create an appropriate illustration.
|
|
109
|
+
|
|
110
|
+
## Related
|
|
111
|
+
|
|
112
|
+
### Patterns
|
|
113
|
+
|
|
114
|
+
* [Errors](../errors/errors.md)
|
|
115
|
+
* [Disabled states](../disabled-states/disabled-states.md)
|
|
116
|
+
|
|
117
|
+
### Components
|
|
118
|
+
|
|
119
|
+
* [Empty state](../EmptyState/EmptyState.md) mobile component
|
|
120
|
+
|
|
121
|
+
## Principles
|
|
122
|
+
|
|
123
|
+
* [Visibility of system status](https://www.nngroup.com/articles/visibility-system-status/)
|
|
124
|
+
* [Consistency and standards](https://www.nngroup.com/articles/consistency-and-standards/)
|
|
125
|
+
* [Aesthetics and minimalist design](https://www.nngroup.com/videos/aesthetic-and-minimalist-design/)
|
|
126
|
+
* [Help users recognize, diagnose and recover from errors](https://www.nngroup.com/articles/ten-usability-heuristics/#toc-9-help-users-recognize-diagnose-and-recover-from-errors-9)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Errors
|
|
2
|
+
|
|
3
|
+
| **Platform** | **Status** |
|
|
4
|
+
| :----------- | :--------- |
|
|
5
|
+
| Web Mobile | Ready |
|
|
6
|
+
|
|
7
|
+
## Goal
|
|
8
|
+
|
|
9
|
+
Inform the user when something is wrong, and equip them with the resources to
|
|
10
|
+
set it right whenever possible.
|
|
11
|
+
|
|
12
|
+
> Good error messages are important, but the best designs carefully prevent
|
|
13
|
+
> problems from occurring in the first place. Either eliminate error-prone
|
|
14
|
+
> conditions, or check for them and present users with a confirmation option
|
|
15
|
+
> before they commit to the action.
|
|
16
|
+
> [– 10 Usability Heuristics for User Interface Design](https://www.nngroup.com/articles/ten-usability-heuristics/#toc-5-error-prevention-5)
|
|
17
|
+
|
|
18
|
+
While avoiding errors is the ideal, it’s largely impossible to avoid *all* of
|
|
19
|
+
the errors, *all* of the time. By being proactive, we can help users recover
|
|
20
|
+
effectively to reduce disruption to their task-at-hand.
|
|
21
|
+
|
|
22
|
+
## Solution
|
|
23
|
+
|
|
24
|
+
First and foremost: design to avoid the possibility of errors!
|
|
25
|
+
|
|
26
|
+
#### Effective content
|
|
27
|
+
|
|
28
|
+
Follow the guidance in our [product vocabulary](../content/product-vocabulary)
|
|
29
|
+
and [voice & tone](../content/voice-and-tone) guides to help you craft effective
|
|
30
|
+
error messages.
|
|
31
|
+
|
|
32
|
+
#### Validation and form inputs
|
|
33
|
+
|
|
34
|
+
Provide a clear, concise message as close as possible to the impacted or
|
|
35
|
+
offending elements.
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
<InputText invalid placeholder="First name" />
|
|
39
|
+
<InputValidation message="First name is required" />
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### System or network errors
|
|
43
|
+
|
|
44
|
+
When an error isn't tied to an inidivual UI element, place a Banner near the
|
|
45
|
+
impacted area. If the issue impacts the entire view, place the banner at the top
|
|
46
|
+
of the view.
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
<Content>
|
|
50
|
+
<Text>Be specific about what went wrong when possible</Text>
|
|
51
|
+
<Banner type="error">
|
|
52
|
+
<Text>Could not connect to the server</Text>
|
|
53
|
+
</Banner>
|
|
54
|
+
<Banner type="error">
|
|
55
|
+
<Text>The network is taking too long to respond</Text>
|
|
56
|
+
</Banner>
|
|
57
|
+
<Text>
|
|
58
|
+
If for whatever reason, we can't provide more detail to the user, use this
|
|
59
|
+
generic fallback message:
|
|
60
|
+
</Text>
|
|
61
|
+
<Banner type="error">
|
|
62
|
+
<Text>Something went wrong. Please try again later.</Text>
|
|
63
|
+
</Banner>
|
|
64
|
+
</Content>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Whenever possible, avoid showing raw error messages (like
|
|
68
|
+
`500 response timeout`) in the app. Write like a human and explain if there's
|
|
69
|
+
anything the user can do to resolve the issue.
|
|
70
|
+
|
|
71
|
+
#### System-wide errors
|
|
72
|
+
|
|
73
|
+
If an issue is not specific to a given screen or user flow, use a "global" error
|
|
74
|
+
message. This should be a banner that runs across the top of the application.
|
|
75
|
+
|
|
76
|
+
#### Empty states
|
|
77
|
+
|
|
78
|
+
If content is missing as a result of the error, follow guidance around
|
|
79
|
+
[empty states.](../empty-states/empty-states.md)
|
|
80
|
+
|
|
81
|
+
## Implementation
|
|
82
|
+
|
|
83
|
+
### Forms and inputs
|
|
84
|
+
|
|
85
|
+
Atlantis inputs like [InputText](../InputText/InputText.md) have input validation
|
|
86
|
+
built-in for ease of use. The input validation is integrated with the
|
|
87
|
+
[Form](../Form/Form.md) components on both web and mobile as well.
|
|
88
|
+
|
|
89
|
+
You can also provide [InputValidation](../components/InputValidation) externally
|
|
90
|
+
if needed.
|
|
91
|
+
|
|
92
|
+
### System-wide feedback
|
|
93
|
+
|
|
94
|
+
Jobber has an internal system called "GlobalBanner" that consolidates all
|
|
95
|
+
system-wide messages for presentation on web and mobile. If something critical
|
|
96
|
+
is occurring related to the user's account, it should be displayed in this
|
|
97
|
+
banner.
|
|
98
|
+
|
|
99
|
+
## Related
|
|
100
|
+
|
|
101
|
+
### Patterns
|
|
102
|
+
|
|
103
|
+
* [Empty states](../empty-states/empty-states.md)
|
|
104
|
+
|
|
105
|
+
### Components
|
|
106
|
+
|
|
107
|
+
* [Banner](../Banner/Banner.md)
|
|
108
|
+
* [InputText](../components/InputValidation)
|
|
109
|
+
* [InputValidation](../components/InputValidation)
|
|
110
|
+
|
|
111
|
+
## Principles
|
|
112
|
+
|
|
113
|
+
* [Visibility of system status](https://www.nngroup.com/articles/visibility-system-status/)
|
|
114
|
+
* [Help users recognize, diagnose and recover from errors](https://www.nngroup.com/articles/ten-usability-heuristics/#toc-9-help-users-recognize-diagnose-and-recover-from-errors-9)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[ActionItem](./ActionItem/ActionItem.md)
|
|
2
|
+
[ActionItemGroup](./ActionItemGroup/ActionItemGroup.md)
|
|
3
|
+
[ActionLabel](./ActionLabel/ActionLabel.md)
|
|
4
|
+
[ActivityIndicator](./ActivityIndicator/ActivityIndicator.md)
|
|
5
|
+
[Animation](./Animation/Animation.md)
|
|
6
|
+
[AtlantisThemeContext](./AtlantisThemeContext/AtlantisThemeContext.md)
|
|
7
|
+
[AutoLink](./AutoLink/AutoLink.md)
|
|
8
|
+
[Banner](./Banner/Banner.md)
|
|
9
|
+
[Borders](./Borders/Borders.md)
|
|
10
|
+
[BottomSheet](./BottomSheet/BottomSheet.md)
|
|
11
|
+
[Button](./Button/Button.md)
|
|
12
|
+
[ButtonGroup](./ButtonGroup/ButtonGroup.md)
|
|
13
|
+
[Card](./Card/Card.md)
|
|
14
|
+
[Checkbox](./Checkbox/Checkbox.md)
|
|
15
|
+
[Chip](./Chip/Chip.md)
|
|
16
|
+
[choosing-components](./choosing-components/choosing-components.md)
|
|
17
|
+
[Colors](./Colors/Colors.md)
|
|
18
|
+
[Content](./Content/Content.md)
|
|
19
|
+
[ContentOverlay](./ContentOverlay/ContentOverlay.md)
|
|
20
|
+
[customizing-components](./customizing-components/customizing-components.md)
|
|
21
|
+
[disabled-states](./disabled-states/disabled-states.md)
|
|
22
|
+
[Disclosure](./Disclosure/Disclosure.md)
|
|
23
|
+
[Divider](./Divider/Divider.md)
|
|
24
|
+
[Elevations](./Elevations/Elevations.md)
|
|
25
|
+
[empty-states](./empty-states/empty-states.md)
|
|
26
|
+
[EmptyState](./EmptyState/EmptyState.md)
|
|
27
|
+
[errors](./errors/errors.md)
|
|
28
|
+
[Flex](./Flex/Flex.md)
|
|
29
|
+
[Form](./Form/Form.md)
|
|
30
|
+
[FormatFile](./FormatFile/FormatFile.md)
|
|
31
|
+
[FormField](./FormField/FormField.md)
|
|
32
|
+
[Glimmer](./Glimmer/Glimmer.md)
|
|
33
|
+
[Heading](./Heading/Heading.md)
|
|
34
|
+
[Icon](./Icon/Icon.md)
|
|
35
|
+
[IconButton](./IconButton/IconButton.md)
|
|
36
|
+
[InputCurrency](./InputCurrency/InputCurrency.md)
|
|
37
|
+
[InputDate](./InputDate/InputDate.md)
|
|
38
|
+
[InputEmail](./InputEmail/InputEmail.md)
|
|
39
|
+
[InputFieldWrapper](./InputFieldWrapper/InputFieldWrapper.md)
|
|
40
|
+
[InputNumber](./InputNumber/InputNumber.md)
|
|
41
|
+
[InputPassword](./InputPassword/InputPassword.md)
|
|
42
|
+
[InputPressable](./InputPressable/InputPressable.md)
|
|
43
|
+
[InputSearch](./InputSearch/InputSearch.md)
|
|
44
|
+
[InputText](./InputText/InputText.md)
|
|
45
|
+
[InputTime](./InputTime/InputTime.md)
|
|
46
|
+
[interaction](./interaction/interaction.md)
|
|
47
|
+
[Opacity](./Opacity/Opacity.md)
|
|
48
|
+
[page-layouts](./page-layouts/page-layouts.md)
|
|
49
|
+
[ProgressBar](./ProgressBar/ProgressBar.md)
|
|
50
|
+
[Radii](./Radii/Radii.md)
|
|
51
|
+
[ResponsiveBreakpoint](./ResponsiveBreakpoint/ResponsiveBreakpoint.md)
|
|
52
|
+
[scaffolding](./scaffolding/scaffolding.md)
|
|
53
|
+
[Select](./Select/Select.md)
|
|
54
|
+
[settings](./settings/settings.md)
|
|
55
|
+
[Spacing](./Spacing/Spacing.md)
|
|
56
|
+
[StatusLabel](./StatusLabel/StatusLabel.md)
|
|
57
|
+
[Switch](./Switch/Switch.md)
|
|
58
|
+
[Text](./Text/Text.md)
|
|
59
|
+
[TextList](./TextList/TextList.md)
|
|
60
|
+
[ThumbnailList](./ThumbnailList/ThumbnailList.md)
|
|
61
|
+
[Toast](./Toast/Toast.md)
|
|
62
|
+
[Typography](./Typography/Typography.md)
|
|
63
|
+
[Typography](./Typography/Typography.md)
|
|
64
|
+
[usage-guidelines](./usage-guidelines/usage-guidelines.md)
|