@jobber/components 9.14.2 → 9.14.4

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.
Files changed (60) hide show
  1. package/dist/ActivityIndicator-cjs.js +1 -1
  2. package/dist/ActivityIndicator-es.js +1 -1
  3. package/dist/ConfirmationModal-cjs.js +1 -1
  4. package/dist/ConfirmationModal-es.js +1 -1
  5. package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +3 -2
  6. package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +3 -2
  7. package/dist/DataList/components/DataListFilters/index.cjs +3 -2
  8. package/dist/DataList/components/DataListFilters/index.mjs +3 -2
  9. package/dist/DataList/components/DataListTotalCount/DataListTotalCount.messages.d.ts +9 -7
  10. package/dist/DataList/index.cjs +1 -0
  11. package/dist/DataList/index.mjs +1 -0
  12. package/dist/DataListTotalCount-cjs.js +11 -9
  13. package/dist/DataListTotalCount-es.js +11 -9
  14. package/dist/DatePicker/index.cjs +2 -1
  15. package/dist/DatePicker/index.mjs +2 -1
  16. package/dist/DatePicker-cjs.js +70 -708
  17. package/dist/DatePicker-es.js +68 -706
  18. package/dist/FilterPicker/FilterPicker.messages.d.ts +51 -0
  19. package/dist/FilterPicker/components/FilterPickerContent/FilterPickerContentHeader/index.cjs +3 -0
  20. package/dist/FilterPicker/components/FilterPickerContent/FilterPickerContentHeader/index.mjs +3 -0
  21. package/dist/FilterPicker/components/FilterPickerContent/FilterPickerContentList/index.cjs +1 -0
  22. package/dist/FilterPicker/components/FilterPickerContent/FilterPickerContentList/index.mjs +1 -0
  23. package/dist/FilterPicker/components/FilterPickerContent/FilterPickerContentSearch/index.cjs +3 -0
  24. package/dist/FilterPicker/components/FilterPickerContent/FilterPickerContentSearch/index.mjs +3 -0
  25. package/dist/FilterPicker/components/FilterPickerContent/index.cjs +3 -2
  26. package/dist/FilterPicker/components/FilterPickerContent/index.mjs +3 -2
  27. package/dist/FilterPicker/components/FilterPickerTrigger/index.cjs +1 -0
  28. package/dist/FilterPicker/components/FilterPickerTrigger/index.mjs +1 -0
  29. package/dist/FilterPicker/index.cjs +3 -2
  30. package/dist/FilterPicker/index.mjs +3 -2
  31. package/dist/FilterPicker.messages-cjs.js +58 -0
  32. package/dist/FilterPicker.messages-es.js +56 -0
  33. package/dist/FilterPickerContentHeader-cjs.js +12 -8
  34. package/dist/FilterPickerContentHeader-es.js +12 -8
  35. package/dist/FilterPickerContentList-cjs.js +10 -10
  36. package/dist/FilterPickerContentList-es.js +10 -10
  37. package/dist/FilterPickerContentSearch-cjs.js +8 -2
  38. package/dist/FilterPickerContentSearch-es.js +8 -2
  39. package/dist/FilterPickerTrigger-cjs.js +7 -2
  40. package/dist/FilterPickerTrigger-es.js +7 -2
  41. package/dist/InputDate/index.cjs +1 -0
  42. package/dist/InputDate/index.mjs +1 -0
  43. package/dist/Spinner-cjs.js +1 -1
  44. package/dist/Spinner-es.js +1 -1
  45. package/dist/dateLocale-cjs.js +1146 -0
  46. package/dist/dateLocale-es.js +1142 -0
  47. package/dist/docs/AtlantisThemeContext/AtlantisThemeContext.md +24 -9
  48. package/dist/docs/FilterPicker/FilterPicker.md +9 -4
  49. package/dist/docs/Icon/Icon.md +1 -0
  50. package/dist/index.cjs +2 -0
  51. package/dist/index.mjs +2 -0
  52. package/dist/sharedHelpers/i18n/dateLocale.d.ts +2 -0
  53. package/dist/sharedHelpers/i18n/index.cjs +3 -0
  54. package/dist/sharedHelpers/i18n/index.d.ts +1 -0
  55. package/dist/sharedHelpers/i18n/index.mjs +1 -0
  56. package/dist/sharedHelpers/i18n/releasedLanguages.d.ts +7 -0
  57. package/dist/sharedHelpers/i18n/useAtlantisI18n.d.ts +17 -6
  58. package/dist/useAtlantisI18n-cjs.js +23 -1
  59. package/dist/useAtlantisI18n-es.js +23 -1
  60. package/package.json +4 -3
@@ -5,16 +5,22 @@ tokens.
5
5
 
6
6
  ## Design & usage guidelines
7
7
 
8
- Both the web and mobile components have the exact same API, except for one minor
9
- difference in how you update the theme.
8
+ Web and mobile both expose Atlantis theme context, but the runtime ownership is
9
+ slightly different across platforms.
10
10
 
11
11
  Each platform provides a `useAtlantisTheme` hook that you may use to access the
12
- `theme` and `tokens` in your components.
12
+ current theme information and design tokens in your components.
13
13
 
14
- On mobile, this hook also returns a `setTheme` function which you'll use to
15
- update the theme for the nearest `AtlantisThemeContextProvider` ancestor.
16
- Typically there will only be a single provider at the root, controlling the
17
- theme for the entire app.
14
+ On mobile, the hook returns:
15
+
16
+ * `theme`: the selected theme preference (`"system" | "light" | "dark"`)
17
+ * `effectiveTheme`: the resolved theme Atlantis uses for tokens
18
+ (`"light" | "dark"`)
19
+ * `tokens`
20
+ * `setTheme`
21
+
22
+ Typically there will only be a single provider at the root, and the consuming
23
+ app will control `theme` and persist that preference outside Atlantis.
18
24
 
19
25
  On web, you'll need to import the `updateTheme` function and call it with the
20
26
  new theme. This is a separate function because it synchronizes the theme update
@@ -86,7 +92,7 @@ function App() {
86
92
  }
87
93
 
88
94
  function ThemedComponent() {
89
- const { theme, tokens, setTheme } = useAtlantisTheme();
95
+ const { theme, effectiveTheme, tokens, setTheme } = useAtlantisTheme();
90
96
  return (
91
97
  <Content>
92
98
  <View
@@ -96,11 +102,16 @@ function ThemedComponent() {
96
102
  }}
97
103
  >
98
104
  <Content>
99
- <Text>The current theme is: {theme}.</Text>
105
+ <Text>The selected theme is: {theme}.</Text>
106
+ <Text>The effective theme is: {effectiveTheme}.</Text>
100
107
  <Text>
101
108
  The javascript tokens can be accessed via the tokens object.
102
109
  </Text>
103
110
  <Text>The theme can be changed using `setTheme`</Text>
111
+ <Button
112
+ onPress={() => setTheme("system")}
113
+ label="The theme can be changed to system"
114
+ />
104
115
  <Button
105
116
  onPress={() => setTheme("light")}
106
117
  label="The theme can be changed to light"
@@ -163,6 +174,10 @@ regardless of the main application theme. This can be done by setting the
163
174
  `dangerouslyOverrideTheme` prop to `<themeToSet>` on the
164
175
  `AtlantisThemeContextProvider`.
165
176
 
177
+ On mobile, forcing a theme changes the rendered tokens for that subtree, but it
178
+ does not replace the selected theme preference semantics from the nearest
179
+ non-forced provider.
180
+
166
181
  Note: If you're using `buildThemedStyles`, any `useStyles` calls must be done
167
182
  within a *child component* of the `AtlantisThemeContextProvider`, not in the
168
183
  same component that renders the provider. Same goes for `useAtlantisTheme`.
@@ -30,6 +30,10 @@ You may also set an optional `subjectNoun` for the FilterPicker content. This
30
30
  will be used in the
31
31
  [empty state](/storybook/web/?path=/story/components-selections-filterpicker--empty-state)
32
32
  of the FilterPicker, as well as the noun within the search placeholder.
33
+ Consumer-provided strings such as `label`, `subjectNoun`, action labels, and
34
+ option labels are rendered as provided and should be localized by the consuming
35
+ application. FilterPicker localizes its own default labels and messages from
36
+ `AtlantisContext.locale`.
33
37
 
34
38
  You may include a prefix element to any `FilterPicker.Option` by setting its
35
39
  `prefix` prop. This could be a [StatusIndicator](../StatusIndicator/StatusIndicator.md) or
@@ -38,9 +42,9 @@ You may include a prefix element to any `FilterPicker.Option` by setting its
38
42
  ### Empty states
39
43
 
40
44
  In cases where the list of options is empty, the FilterPicker content will
41
- display a message indicating the absence of options. The default will read, *"No
42
- options yet"* or *"You don't have any \[subjectNoun] yet"* if you've set the
43
- `subjectNoun` prop.
45
+ display a localized message indicating the absence of options. In English, the
46
+ default reads *"No options yet"* or *"You don't have any \[subjectNoun] yet"* if
47
+ you've set the `subjectNoun` prop.
44
48
 
45
49
  If options are available, but the search query does not match any of them, the
46
50
  FilterPicker Content will display a message indicating that no options match the
@@ -87,7 +91,8 @@ and
87
91
  [multi-select](/storybook/web/?path=/story/components-selections-filterpicker--multi-select)
88
92
  stories. The label of the default activator can be customized by adding the
89
93
  optional `label` prop to FilterPicker, to better reflect the type of data being
90
- selected. Otherwise, the default activator label will read "Select".
94
+ selected. Otherwise, the default activator label is localized from
95
+ `AtlantisContext.locale`; in English, it reads "Select".
91
96
 
92
97
  The optional `label` prop on FilterPicker is only effective when using the
93
98
  default activator.
@@ -521,6 +521,7 @@ export function IconSizesExample() {
521
521
  | | `partlySunny` |
522
522
  | | `snow` |
523
523
  | | `thunderLightening` |
524
+ | | `windy` |
524
525
 
525
526
  ### Legacy
526
527
 
package/dist/index.cjs CHANGED
@@ -137,6 +137,7 @@ require('./_baseEach-cjs.js');
137
137
  require('./debounce-cjs.js');
138
138
  require('./FilterPickerContent-cjs.js');
139
139
  require('./FilterPickerContentSearch-cjs.js');
140
+ require('./FilterPicker.messages-cjs.js');
140
141
  require('./FilterPickerContentList-cjs.js');
141
142
  require('framer-motion');
142
143
  require('./FilterPickerOption-cjs.js');
@@ -182,6 +183,7 @@ require('./DataListLoadMore-cjs.js');
182
183
  require('./DataListAction-cjs.js');
183
184
  require('./DataListLayoutActions-cjs.js');
184
185
  require('./DataListStatusBar-cjs.js');
186
+ require('./dateLocale-cjs.js');
185
187
  require('./ScrollAreaViewport-cjs.js');
186
188
  require('./scrollEdges-cjs.js');
187
189
  require('./OverlaySeparator-cjs.js');
package/dist/index.mjs CHANGED
@@ -135,6 +135,7 @@ import './_baseEach-es.js';
135
135
  import './debounce-es.js';
136
136
  import './FilterPickerContent-es.js';
137
137
  import './FilterPickerContentSearch-es.js';
138
+ import './FilterPicker.messages-es.js';
138
139
  import './FilterPickerContentList-es.js';
139
140
  import 'framer-motion';
140
141
  import './FilterPickerOption-es.js';
@@ -180,6 +181,7 @@ import './DataListLoadMore-es.js';
180
181
  import './DataListAction-es.js';
181
182
  import './DataListLayoutActions-es.js';
182
183
  import './DataListStatusBar-es.js';
184
+ import './dateLocale-es.js';
183
185
  import './ScrollAreaViewport-es.js';
184
186
  import './scrollEdges-es.js';
185
187
  import './OverlaySeparator-es.js';
@@ -0,0 +1,2 @@
1
+ export declare function getDateLocale(locale: string): import("date-fns").Locale;
2
+ export declare function useDateLocale(): import("date-fns").Locale;
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var common_messages = require('../../common.messages-cjs.js');
4
+ var dateLocale = require('../../dateLocale-cjs.js');
4
5
  var useAtlantisI18n = require('../../useAtlantisI18n-cjs.js');
5
6
  require('react');
6
7
  require('../../AtlantisContext-cjs.js');
@@ -8,6 +9,8 @@ require('../../AtlantisContext-cjs.js');
8
9
 
9
10
 
10
11
  exports.commonMessages = common_messages.commonMessages;
12
+ exports.getDateLocale = dateLocale.getDateLocale;
13
+ exports.useDateLocale = dateLocale.useDateLocale;
11
14
  exports.defineMessages = useAtlantisI18n.defineMessages;
12
15
  exports.useAtlantisI18n = useAtlantisI18n.useAtlantisI18n;
13
16
  exports.useReleasedLocale = useAtlantisI18n.useReleasedLocale;
@@ -1,4 +1,5 @@
1
1
  export { commonMessages } from "./common.messages";
2
+ export { getDateLocale, useDateLocale } from "./dateLocale";
2
3
  export { defineMessages, useAtlantisI18n } from "./useAtlantisI18n";
3
4
  export type { AtlantisMessages } from "./useAtlantisI18n";
4
5
  export { useReleasedLocale } from "./useReleasedLocale";
@@ -1,4 +1,5 @@
1
1
  export { c as commonMessages } from '../../common.messages-es.js';
2
+ export { g as getDateLocale, u as useDateLocale } from '../../dateLocale-es.js';
2
3
  export { d as defineMessages, u as useAtlantisI18n, a as useReleasedLocale } from '../../useAtlantisI18n-es.js';
3
4
  import 'react';
4
5
  import '../../AtlantisContext-es.js';
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Languages that have been fully released and are safe to surface to users.
3
+ * Any locale whose language tag is not in this list will fall back to "en".
4
+ *
5
+ * To release a new language, add its BCP 47 language tag here (e.g. "es").
6
+ */
7
+ export declare const RELEASED_LANGUAGES: readonly string[];
1
8
  /**
2
9
  * Returns the locale to use based on what has been released. Matches on the
3
10
  * language part of the locale (before the "-") so that regional variants like
@@ -1,13 +1,24 @@
1
+ type MessageValues = Record<string, string | number>;
2
+ type PluralMessage = Readonly<Partial<Record<Intl.LDMLPluralRule, string>> & {
3
+ readonly other: string;
4
+ }>;
5
+ interface LocalizedMessage<Message> {
6
+ readonly en: Message;
7
+ readonly [locale: string]: Message;
8
+ }
9
+ type AtlantisMessage = LocalizedMessage<string> | LocalizedMessage<PluralMessage>;
1
10
  export interface AtlantisMessages {
2
- readonly [messageKey: string]: {
3
- readonly en: string;
4
- readonly [locale: string]: string;
5
- };
11
+ readonly [messageKey: string]: AtlantisMessage;
6
12
  }
7
- type MessageValues = Record<string, string | number>;
13
+ type MessageKeyOfType<Messages extends AtlantisMessages, Message> = {
14
+ readonly [MessageKey in keyof Messages]: Messages[MessageKey] extends Message ? MessageKey : never;
15
+ }[keyof Messages];
16
+ export type TextMessageKey<Messages extends AtlantisMessages> = MessageKeyOfType<Messages, LocalizedMessage<string>>;
17
+ type PluralMessageKey<Messages extends AtlantisMessages> = MessageKeyOfType<Messages, LocalizedMessage<PluralMessage>>;
8
18
  export declare function defineMessages<Messages extends AtlantisMessages>(messages: Messages): Messages;
9
19
  export declare function useAtlantisI18n<Messages extends AtlantisMessages>(messages: Messages): {
10
20
  readonly locale: string;
11
- readonly t: (messageKey: keyof Messages, values?: MessageValues) => string;
21
+ readonly t: (messageKey: TextMessageKey<Messages>, values?: MessageValues) => string;
22
+ readonly plural: (messageKey: PluralMessageKey<Messages>, count: number, values?: MessageValues) => string;
12
23
  };
13
24
  export {};
@@ -47,7 +47,29 @@ function useAtlantisI18n(messages) {
47
47
  const t = React.useCallback((messageKey, values) => {
48
48
  return interpolateMessage(resolveMessage(messages[messageKey], locale), values);
49
49
  }, [locale, messages]);
50
- return { locale, t };
50
+ const plural = React.useCallback((messageKey, count, values) => {
51
+ var _a;
52
+ const pluralMessage = resolveMessage(messages[messageKey], locale);
53
+ const pluralCategory = createPluralRules(locale).select(count);
54
+ const message = (_a = pluralMessage[pluralCategory]) !== null && _a !== void 0 ? _a : pluralMessage.other;
55
+ return interpolateMessage(message, Object.assign(Object.assign({}, values), { count }));
56
+ }, [locale, messages]);
57
+ return { locale, plural, t };
58
+ }
59
+ const pluralRulesCache = new Map();
60
+ function createPluralRules(locale) {
61
+ const cachedPluralRules = pluralRulesCache.get(locale);
62
+ if (cachedPluralRules)
63
+ return cachedPluralRules;
64
+ let pluralRules;
65
+ try {
66
+ pluralRules = new Intl.PluralRules(locale);
67
+ }
68
+ catch (_a) {
69
+ pluralRules = new Intl.PluralRules("en");
70
+ }
71
+ pluralRulesCache.set(locale, pluralRules);
72
+ return pluralRules;
51
73
  }
52
74
  function resolveMessage(message, locale) {
53
75
  var _a, _b;
@@ -45,7 +45,29 @@ function useAtlantisI18n(messages) {
45
45
  const t = useCallback((messageKey, values) => {
46
46
  return interpolateMessage(resolveMessage(messages[messageKey], locale), values);
47
47
  }, [locale, messages]);
48
- return { locale, t };
48
+ const plural = useCallback((messageKey, count, values) => {
49
+ var _a;
50
+ const pluralMessage = resolveMessage(messages[messageKey], locale);
51
+ const pluralCategory = createPluralRules(locale).select(count);
52
+ const message = (_a = pluralMessage[pluralCategory]) !== null && _a !== void 0 ? _a : pluralMessage.other;
53
+ return interpolateMessage(message, Object.assign(Object.assign({}, values), { count }));
54
+ }, [locale, messages]);
55
+ return { locale, plural, t };
56
+ }
57
+ const pluralRulesCache = new Map();
58
+ function createPluralRules(locale) {
59
+ const cachedPluralRules = pluralRulesCache.get(locale);
60
+ if (cachedPluralRules)
61
+ return cachedPluralRules;
62
+ let pluralRules;
63
+ try {
64
+ pluralRules = new Intl.PluralRules(locale);
65
+ }
66
+ catch (_a) {
67
+ pluralRules = new Intl.PluralRules("en");
68
+ }
69
+ pluralRulesCache.set(locale, pluralRules);
70
+ return pluralRules;
49
71
  }
50
72
  function resolveMessage(message, locale) {
51
73
  var _a, _b;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components",
3
- "version": "9.14.2",
3
+ "version": "9.14.4",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -481,6 +481,7 @@
481
481
  "axios": "^1.18.0",
482
482
  "classnames": "^2.3.2",
483
483
  "color": "^3.1.2",
484
+ "date-fns": "^4.1.0",
484
485
  "filesize": "^6.1.0",
485
486
  "framer-motion": "^11.11.12",
486
487
  "lodash": "^4.17.21",
@@ -495,7 +496,7 @@
495
496
  "devDependencies": {
496
497
  "@apollo/client": "^3.7.10",
497
498
  "@csstools/postcss-global-data": "^1.0.3",
498
- "@jobber/design": "0.114.0",
499
+ "@jobber/design": "0.115.0",
499
500
  "@jobber/hooks": "2.21.1",
500
501
  "@rollup/plugin-alias": "^5.1.0",
501
502
  "@rollup/plugin-commonjs": "^25.0.7",
@@ -547,5 +548,5 @@
547
548
  "> 1%",
548
549
  "IE 10"
549
550
  ],
550
- "gitHead": "e4dbbfa3535d42741ca8622ccb33275f4284edd3"
551
+ "gitHead": "982281f5f4ae2c3fce9ac0f09960bafdb1651d64"
551
552
  }