@strato-admin/cloudscape 0.1.0 → 0.3.0

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 (231) hide show
  1. package/dist/Admin.d.ts +6 -2
  2. package/dist/Admin.js +14 -8
  3. package/dist/RecordLink.js +5 -4
  4. package/dist/Settings.d.ts +17 -0
  5. package/dist/Settings.js +14 -0
  6. package/dist/button/BulkDeleteButton.d.ts +4 -1
  7. package/dist/button/BulkDeleteButton.js +37 -5
  8. package/dist/button/Button.d.ts +2 -1
  9. package/dist/button/CancelButton.d.ts +6 -0
  10. package/dist/button/CancelButton.js +10 -0
  11. package/dist/button/CreateButton.js +9 -8
  12. package/dist/button/DeleteButton.d.ts +13 -0
  13. package/dist/button/DeleteButton.js +36 -0
  14. package/dist/button/EditButton.d.ts +1 -1
  15. package/dist/button/EditButton.js +10 -10
  16. package/dist/button/SaveButton.js +2 -2
  17. package/dist/button/index.d.ts +2 -0
  18. package/dist/button/index.js +2 -0
  19. package/dist/collection-hooks/interfaces.d.ts +7 -3
  20. package/dist/collection-hooks/useCollection.d.ts +1 -1
  21. package/dist/collection-hooks/useCollection.js +15 -10
  22. package/dist/create/Create.d.ts +9 -17
  23. package/dist/create/Create.js +40 -12
  24. package/dist/create/CreateHeader.d.ts +2 -2
  25. package/dist/create/CreateHeader.js +4 -5
  26. package/dist/defaults.d.ts +6 -0
  27. package/dist/defaults.js +21 -0
  28. package/dist/detail/Detail.d.ts +33 -0
  29. package/dist/detail/Detail.js +22 -0
  30. package/dist/detail/DetailHeader.d.ts +11 -0
  31. package/dist/detail/{ShowHeader.js → DetailHeader.js} +7 -5
  32. package/dist/detail/DetailHub.d.ts +27 -0
  33. package/dist/detail/DetailHub.js +63 -0
  34. package/dist/detail/KeyValuePairs.d.ts +7 -1
  35. package/dist/detail/KeyValuePairs.js +14 -8
  36. package/dist/detail/index.d.ts +3 -2
  37. package/dist/detail/index.js +3 -2
  38. package/dist/edit/Edit.d.ts +8 -19
  39. package/dist/edit/Edit.js +48 -12
  40. package/dist/edit/EditHeader.d.ts +2 -2
  41. package/dist/edit/EditHeader.js +5 -4
  42. package/dist/field/ArrayField.d.ts +26 -10
  43. package/dist/field/ArrayField.js +38 -10
  44. package/dist/field/BadgeField.d.ts +1 -1
  45. package/dist/field/BadgeField.js +1 -1
  46. package/dist/field/BooleanField.d.ts +1 -1
  47. package/dist/field/BooleanField.js +2 -2
  48. package/dist/field/CurrencyField.d.ts +1 -1
  49. package/dist/field/CurrencyField.js +1 -1
  50. package/dist/field/DateField.d.ts +1 -1
  51. package/dist/field/DateField.js +1 -1
  52. package/dist/field/IdField.d.ts +1 -1
  53. package/dist/field/IdField.js +3 -3
  54. package/dist/field/NumberField.d.ts +1 -1
  55. package/dist/field/NumberField.js +1 -1
  56. package/dist/field/ReferenceField.d.ts +1 -1
  57. package/dist/field/ReferenceField.js +4 -2
  58. package/dist/field/ReferenceManyField.d.ts +35 -4
  59. package/dist/field/ReferenceManyField.js +17 -4
  60. package/dist/field/StatusIndicatorField.d.ts +1 -1
  61. package/dist/field/StatusIndicatorField.js +6 -5
  62. package/dist/field/TextField.d.ts +1 -1
  63. package/dist/field/TextField.js +1 -1
  64. package/dist/field/types.d.ts +9 -9
  65. package/dist/form/Form.d.ts +12 -2
  66. package/dist/form/Form.js +10 -16
  67. package/dist/form/index.d.ts +1 -1
  68. package/dist/form/index.js +1 -1
  69. package/dist/hooks/useSchemaFields.d.ts +22 -0
  70. package/dist/hooks/useSchemaFields.js +45 -0
  71. package/dist/i18n/Message.d.ts +15 -0
  72. package/dist/i18n/Message.js +19 -0
  73. package/dist/i18n/RecordMessage.d.ts +14 -0
  74. package/dist/i18n/RecordMessage.js +16 -0
  75. package/dist/i18n/index.d.ts +3 -0
  76. package/dist/i18n/index.js +2 -0
  77. package/dist/i18n/types.d.ts +19 -0
  78. package/dist/i18n/types.js +1 -0
  79. package/dist/index.d.ts +5 -1
  80. package/dist/index.js +5 -1
  81. package/dist/input/ArrayInput.d.ts +33 -0
  82. package/dist/input/{AttributeEditor.js → ArrayInput.js} +18 -11
  83. package/dist/input/AutocompleteInput.d.ts +1 -1
  84. package/dist/input/AutocompleteInput.js +3 -3
  85. package/dist/input/BooleanInput.d.ts +6 -0
  86. package/dist/input/BooleanInput.js +23 -0
  87. package/dist/input/CommonInputProps.d.ts +6 -0
  88. package/dist/input/CommonInputProps.js +6 -0
  89. package/dist/input/FieldTitle.js +4 -4
  90. package/dist/input/FormField.js +12 -3
  91. package/dist/input/FormFieldContext.d.ts +1 -1
  92. package/dist/input/NumberInput.d.ts +1 -1
  93. package/dist/input/NumberInput.js +3 -3
  94. package/dist/input/ReferenceInput.d.ts +1 -1
  95. package/dist/input/ReferenceInput.js +22 -12
  96. package/dist/input/SelectInput.d.ts +1 -1
  97. package/dist/input/SelectInput.js +3 -3
  98. package/dist/input/SliderInput.d.ts +1 -1
  99. package/dist/input/SliderInput.js +4 -4
  100. package/dist/input/TextAreaInput.d.ts +1 -1
  101. package/dist/input/TextAreaInput.js +3 -3
  102. package/dist/input/TextInput.d.ts +1 -1
  103. package/dist/input/TextInput.js +6 -12
  104. package/dist/input/index.d.ts +2 -1
  105. package/dist/input/index.js +2 -1
  106. package/dist/input/types.d.ts +33 -2
  107. package/dist/layout/AppLayout.js +6 -3
  108. package/dist/layout/Notifications.d.ts +1 -0
  109. package/dist/layout/Notifications.js +51 -0
  110. package/dist/layout/Ready.d.ts +6 -0
  111. package/dist/layout/Ready.js +24 -0
  112. package/dist/layout/TopNavigation.d.ts +4 -2
  113. package/dist/layout/TopNavigation.js +7 -7
  114. package/dist/layout/index.d.ts +2 -0
  115. package/dist/layout/index.js +2 -0
  116. package/dist/list/Cards.d.ts +31 -4
  117. package/dist/list/Cards.js +81 -10
  118. package/dist/list/List.d.ts +9 -12
  119. package/dist/list/List.js +41 -11
  120. package/dist/list/Table.d.ts +8 -4
  121. package/dist/list/Table.js +55 -55
  122. package/dist/list/TableHeader.d.ts +2 -2
  123. package/dist/list/TableHeader.js +4 -5
  124. package/dist/theme/ThemeManager.js +1 -1
  125. package/package.json +9 -6
  126. package/src/Admin.tsx +35 -18
  127. package/src/RecordLink.stories.tsx +1 -1
  128. package/src/RecordLink.tsx +5 -4
  129. package/src/Settings.tsx +16 -0
  130. package/src/__mocks__/ra-core.tsx +83 -0
  131. package/src/__mocks__/strato-core.tsx +36 -42
  132. package/src/button/BulkDeleteButton.test.tsx +45 -8
  133. package/src/button/BulkDeleteButton.tsx +75 -12
  134. package/src/button/Button.tsx +31 -2
  135. package/src/button/CancelButton.tsx +20 -0
  136. package/src/button/CreateButton.tsx +12 -10
  137. package/src/button/DeleteButton.tsx +96 -0
  138. package/src/button/EditButton.tsx +13 -12
  139. package/src/button/SaveButton.tsx +2 -3
  140. package/src/button/index.ts +2 -0
  141. package/src/collection-hooks/interfaces.ts +7 -3
  142. package/src/collection-hooks/useCollection.test.ts +115 -2
  143. package/src/collection-hooks/useCollection.ts +15 -10
  144. package/src/create/Create.test.tsx +3 -3
  145. package/src/create/Create.tsx +68 -37
  146. package/src/create/CreateHeader.tsx +6 -10
  147. package/src/defaults.tsx +28 -0
  148. package/src/detail/Detail-CollectionFields.test.tsx +84 -0
  149. package/src/detail/Detail.test.tsx +91 -0
  150. package/src/detail/Detail.tsx +48 -0
  151. package/src/detail/{ShowHeader.test.tsx → DetailHeader.test.tsx} +11 -9
  152. package/src/detail/DetailHeader.tsx +42 -0
  153. package/src/detail/DetailHub.tsx +88 -0
  154. package/src/detail/KeyValuePairs.test.tsx +2 -2
  155. package/src/detail/KeyValuePairs.tsx +25 -18
  156. package/src/detail/index.ts +3 -2
  157. package/src/edit/Edit.test.tsx +7 -5
  158. package/src/edit/Edit.tsx +92 -40
  159. package/src/edit/EditHeader.tsx +7 -5
  160. package/src/field/ArrayField.tsx +57 -11
  161. package/src/field/BadgeField.tsx +2 -3
  162. package/src/field/BooleanField.test.tsx +2 -3
  163. package/src/field/BooleanField.tsx +3 -3
  164. package/src/field/CurrencyField.tsx +1 -1
  165. package/src/field/DateField.tsx +1 -1
  166. package/src/field/IdField.test.tsx +8 -20
  167. package/src/field/IdField.tsx +5 -20
  168. package/src/field/NumberField.tsx +1 -1
  169. package/src/field/ReferenceField.test.tsx +15 -6
  170. package/src/field/ReferenceField.tsx +10 -7
  171. package/src/field/ReferenceManyField.test.tsx +55 -10
  172. package/src/field/ReferenceManyField.tsx +84 -13
  173. package/src/field/StatusIndicatorField.test.tsx +7 -21
  174. package/src/field/StatusIndicatorField.tsx +8 -20
  175. package/src/field/TextField.tsx +1 -1
  176. package/src/field/types.ts +12 -13
  177. package/src/form/Form.test.tsx +8 -4
  178. package/src/form/Form.tsx +24 -19
  179. package/src/form/index.ts +1 -1
  180. package/src/hooks/useSchemaFields.ts +89 -0
  181. package/src/i18n/Message.tsx +22 -0
  182. package/src/i18n/RecordMessage.tsx +22 -0
  183. package/src/i18n/index.ts +3 -0
  184. package/src/i18n/types.ts +19 -0
  185. package/src/index.ts +5 -1
  186. package/src/input/ArrayInput.test.tsx +81 -0
  187. package/src/input/{AttributeEditor.tsx → ArrayInput.tsx} +36 -18
  188. package/src/input/AutocompleteInput.test.tsx +2 -4
  189. package/src/input/AutocompleteInput.tsx +9 -11
  190. package/src/input/BooleanInput.tsx +42 -0
  191. package/src/input/CommonInputProps.tsx +8 -0
  192. package/src/input/FieldTitle.tsx +3 -15
  193. package/src/input/FormField.tsx +78 -67
  194. package/src/input/FormFieldContext.ts +1 -1
  195. package/src/input/NumberInput.tsx +10 -7
  196. package/src/input/ReferenceInput.test.tsx +12 -2
  197. package/src/input/ReferenceInput.tsx +32 -14
  198. package/src/input/SelectInput.tsx +14 -17
  199. package/src/input/SliderInput.test.tsx +2 -3
  200. package/src/input/SliderInput.tsx +48 -38
  201. package/src/input/TextAreaInput.tsx +10 -6
  202. package/src/input/TextInput.test.tsx +2 -4
  203. package/src/input/TextInput.tsx +35 -20
  204. package/src/input/index.ts +2 -1
  205. package/src/input/types.ts +40 -8
  206. package/src/layout/AppLayout.test.tsx +23 -3
  207. package/src/layout/AppLayout.tsx +11 -8
  208. package/src/layout/Notifications.test.tsx +102 -0
  209. package/src/layout/Notifications.tsx +61 -0
  210. package/src/layout/Ready.tsx +123 -0
  211. package/src/layout/TopNavigation.test.tsx +2 -3
  212. package/src/layout/TopNavigation.tsx +9 -8
  213. package/src/layout/index.ts +2 -0
  214. package/src/list/Cards.test.tsx +320 -0
  215. package/src/list/Cards.tsx +146 -16
  216. package/src/list/List.tsx +87 -26
  217. package/src/list/Table.test.tsx +40 -5
  218. package/src/list/Table.tsx +89 -98
  219. package/src/list/TableHeader.test.tsx +15 -11
  220. package/src/list/TableHeader.tsx +6 -8
  221. package/src/theme/ThemeManager.tsx +1 -1
  222. package/dist/__mocks__/strato-core.js +0 -50
  223. package/dist/__mocks__to__delete/strato-core.js +0 -50
  224. package/dist/detail/Show.d.ts +0 -39
  225. package/dist/detail/Show.js +0 -40
  226. package/dist/detail/ShowHeader.d.ts +0 -7
  227. package/dist/input/AttributeEditor.d.ts +0 -25
  228. package/src/detail/Show.test.tsx +0 -96
  229. package/src/detail/Show.tsx +0 -104
  230. package/src/detail/ShowHeader.tsx +0 -35
  231. package/src/input/AttributeEditor.test.tsx +0 -147
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React, { useMemo } from 'react';
3
- import { useInput, RecordContextProvider, useResourceContext } from '@strato-admin/core';
3
+ import { useInput, RecordContextProvider, useResourceContext } from '@strato-admin/ra-core';
4
4
  import { useFieldArray, useFormContext } from 'react-hook-form';
5
5
  import CloudscapeAttributeEditor from '@cloudscape-design/components/attribute-editor';
6
6
  import Box from '@cloudscape-design/components/box';
@@ -10,11 +10,14 @@ import FormField from './FormField';
10
10
  import { FormFieldContext, useFormFieldContext } from './FormFieldContext';
11
11
  export const Item = (_props) => {
12
12
  // This is a placeholder component used to collect props.
13
- // The actual rendering is handled by the AttributeEditor.
13
+ // The actual rendering is handled by the ArrayInput.
14
14
  return null;
15
15
  };
16
- export const AttributeEditor = (props) => {
17
- const { children, label, source: sourceProp, validate, defaultValue, addButtonText = 'Add item', removeButtonText = 'Remove item', empty, disableAddButton, hideAddButton, ...rest } = props;
16
+ /**
17
+ * ArrayInput component that uses Cloudscape's AttributeEditor to edit arrays of objects.
18
+ */
19
+ export const ArrayInput = (props) => {
20
+ const { children, label, source: sourceProp, validate, defaultValue, addButtonText = 'Add item', removeButtonText = 'Remove item', empty, disableAddButton, hideAddButton, gridLayout, ...rest } = props;
18
21
  const { control } = useFormContext();
19
22
  const contextValue = useFormFieldContext();
20
23
  const resource = useResourceContext();
@@ -45,12 +48,16 @@ export const AttributeEditor = (props) => {
45
48
  const childSource = childProps.source;
46
49
  const childLabel = childProps.label;
47
50
  const childValidate = childProps.validate;
51
+ const childDescription = childProps.description;
52
+ const childInfo = childProps.info;
48
53
  // Determine if the field is required by checking validators
49
54
  const isRequired = Array.isArray(childValidate)
50
- ? childValidate.some((v) => v.isRequired)
51
- : childValidate?.isRequired || childProps.isRequired;
55
+ ? childValidate.some((v) => v.isRequired || v.name === 'required')
56
+ : childValidate?.isRequired || childValidate?.name === 'required' || childProps.isRequired;
52
57
  return {
53
- label: _jsx(FieldTitle, { label: childLabel, source: childSource, resource: resource, isRequired: isRequired }),
58
+ label: (_jsx(FieldTitle, { label: childLabel, source: childSource, resource: childProps.resource || resource, isRequired: isRequired })),
59
+ description: childDescription,
60
+ info: childInfo,
54
61
  control: (item, index) => {
55
62
  const prefixedSource = `${source}.${index}.${childSource}`;
56
63
  let content;
@@ -65,16 +72,16 @@ export const AttributeEditor = (props) => {
65
72
  label: false,
66
73
  });
67
74
  }
68
- return (_jsx(RecordContextProvider, { value: item, children: _jsx(Box, { padding: { top: 's' }, children: content }) }));
75
+ return _jsx(RecordContextProvider, { value: item, children: content });
69
76
  },
70
77
  };
71
78
  })?.filter(Boolean);
72
79
  }, [children, source, resource]);
73
- const inner = (_jsx(FormFieldContext.Provider, { value: undefined, children: _jsx(CloudscapeAttributeEditor, { items: fields, definition: definition, onAddButtonClick: handleAdd, onRemoveButtonClick: ({ detail: { itemIndex } }) => handleRemove(itemIndex), empty: empty || (_jsx(Box, { textAlign: "center", color: "inherit", children: "No items added yet." })), addButtonText: addButtonText, removeButtonText: removeButtonText, disableAddButton: disableAddButton, hideAddButton: hideAddButton }) }));
80
+ const inner = (_jsx(FormFieldContext.Provider, { value: undefined, children: _jsx(CloudscapeAttributeEditor, { items: fields, definition: definition, onAddButtonClick: handleAdd, onRemoveButtonClick: ({ detail: { itemIndex } }) => handleRemove(itemIndex), empty: empty || (_jsx(Box, { textAlign: "center", color: "inherit", children: "No items added yet." })), addButtonText: addButtonText, removeButtonText: removeButtonText, disableAddButton: disableAddButton, hideAddButton: hideAddButton, gridLayout: gridLayout }) }));
74
81
  if (contextValue) {
75
82
  return inner;
76
83
  }
77
84
  return (_jsx(FormFieldContext.Provider, { value: { ...inputState, source }, children: _jsx(FormField, { ...props, source: source, children: inner }) }));
78
85
  };
79
- AttributeEditor.Item = Item;
80
- export default AttributeEditor;
86
+ ArrayInput.Item = Item;
87
+ export default ArrayInput;
@@ -1,6 +1,6 @@
1
1
  import { AutosuggestProps as CloudscapeAutosuggestProps } from '@cloudscape-design/components/autosuggest';
2
2
  import { InputProps } from './types';
3
- export interface AutocompleteInputProps extends Omit<CloudscapeAutosuggestProps, 'onChange' | 'value' | 'options' | 'onBlur'>, InputProps {
3
+ export interface AutocompleteInputProps extends InputProps, Pick<CloudscapeAutosuggestProps, 'placeholder' | 'disabled' | 'readOnly' | 'enteredTextLabel'> {
4
4
  choices?: Array<{
5
5
  id: string | number;
6
6
  [key: string]: any;
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React, { useState, useEffect, useMemo } from 'react';
3
- import { useInput, useResourceContext, useChoicesContext, useGetRecordRepresentation, } from '@strato-admin/core';
3
+ import { useInput, useResourceContext, useChoicesContext, useGetRecordRepresentation } from '@strato-admin/ra-core';
4
4
  import CloudscapeAutosuggest from '@cloudscape-design/components/autosuggest';
5
5
  import { FormField } from './FormField';
6
6
  import { FormFieldContext, useFormFieldContext } from './FormFieldContext';
7
7
  export const AutocompleteInput = (props) => {
8
- const { label, source, defaultValue, validate, choices: choicesProp, ...rest } = props;
8
+ const { label, source, defaultValue, validate, choices: choicesProp, placeholder, disabled, readOnly, enteredTextLabel, ...rest } = props;
9
9
  const resource = useResourceContext();
10
10
  const { allChoices, isPending, setFilters } = useChoicesContext(props);
11
11
  const getRecordRepresentation = useGetRecordRepresentation(resource);
@@ -58,7 +58,7 @@ export const AutocompleteInput = (props) => {
58
58
  const handleSelect = ({ detail }) => {
59
59
  field.onChange(detail.value);
60
60
  };
61
- const inner = (_jsx(CloudscapeAutosuggest, { ...rest, id: id, options: options, value: filterValue, statusType: isPending ? 'loading' : 'finished', expandToViewport: true, onChange: handleChange, onSelect: handleSelect, onBlur: () => field.onBlur() }));
61
+ const inner = (_jsx(CloudscapeAutosuggest, { id: id, placeholder: placeholder, disabled: disabled, readOnly: readOnly, enteredTextLabel: enteredTextLabel, options: options, value: filterValue, statusType: isPending ? 'loading' : 'finished', expandToViewport: true, onChange: handleChange, onSelect: handleSelect, onBlur: () => field.onBlur() }));
62
62
  if (context) {
63
63
  return inner;
64
64
  }
@@ -0,0 +1,6 @@
1
+ import { ToggleProps } from '@cloudscape-design/components/toggle';
2
+ import { InputProps } from './types';
3
+ export interface BooleanInputProps extends InputProps, Pick<ToggleProps, 'disabled' | 'readOnly' | 'children' | 'ariaLabel'> {
4
+ }
5
+ export declare const BooleanInput: (props: BooleanInputProps) => import("react/jsx-runtime").JSX.Element;
6
+ export default BooleanInput;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useInput } from '@strato-admin/ra-core';
3
+ import Toggle from '@cloudscape-design/components/toggle';
4
+ import { FormField } from './FormField';
5
+ import { FormFieldContext, useFormFieldContext } from './FormFieldContext';
6
+ export const BooleanInput = (props) => {
7
+ const { label, source, defaultValue, validate, disabled, readOnly, children, ariaLabel, ...rest } = props;
8
+ const context = useFormFieldContext();
9
+ const inputState = context ??
10
+ useInput({
11
+ source,
12
+ defaultValue: defaultValue ?? false,
13
+ validate,
14
+ ...rest,
15
+ });
16
+ const { field } = inputState;
17
+ const inner = (_jsx(Toggle, { disabled: disabled, readOnly: readOnly, ariaLabel: ariaLabel, checked: !!field.value, onChange: (event) => field.onChange(event.detail.checked), children: children }));
18
+ if (context) {
19
+ return inner;
20
+ }
21
+ return (_jsx(FormFieldContext.Provider, { value: inputState, children: _jsx(FormField, { ...props, children: inner }) }));
22
+ };
23
+ export default BooleanInput;
@@ -0,0 +1,6 @@
1
+ import { StratoCommonInputProps } from './types';
2
+ /**
3
+ * @internal Stub component for react-docgen-typescript to extract StratoCommonInputProps.
4
+ * Not intended for direct use.
5
+ */
6
+ export declare const CommonInputProps: (_props: StratoCommonInputProps) => null;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @internal Stub component for react-docgen-typescript to extract StratoCommonInputProps.
3
+ * Not intended for direct use.
4
+ */
5
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
6
+ export const CommonInputProps = (_props) => null;
@@ -1,9 +1,9 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React from 'react';
3
- import { useTranslate, useResourceDefinitions } from '@strato-admin/core';
3
+ import { useTranslate, useResourceDefinitions } from '@strato-admin/ra-core';
4
4
  import { humanize } from 'inflection';
5
5
  export const FieldTitle = (props) => {
6
- const { resource, source, label, isRequired } = props;
6
+ const { resource, source, label } = props;
7
7
  const translate = useTranslate();
8
8
  const definitions = useResourceDefinitions();
9
9
  const labelString = React.useMemo(() => {
@@ -24,6 +24,6 @@ export const FieldTitle = (props) => {
24
24
  _: defaultLabel,
25
25
  });
26
26
  }, [label, translate, resource, source, definitions]);
27
- return (_jsxs("span", { children: [labelString, !isRequired && (_jsx("span", { style: { color: '#687078', fontWeight: 'normal', fontStyle: 'italic', fontSize: '12px', marginLeft: '4px' }, children: "(optional)" }))] }));
27
+ return _jsx("span", { children: labelString });
28
28
  };
29
29
  export default FieldTitle;
@@ -1,12 +1,13 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
- import { useInput, useResourceContext, ValidationError } from '@strato-admin/core';
3
+ import { useInput, useResourceContext, ValidationError, useTranslate } from '@strato-admin/ra-core';
4
4
  import CloudscapeFormField from '@cloudscape-design/components/form-field';
5
5
  import { FieldTitle } from './FieldTitle';
6
6
  import { FormFieldContext, useFormFieldContext } from './FormFieldContext';
7
7
  export const FormField = (props) => {
8
8
  const { children, label, source, defaultValue, validate, description, constraintText, info, secondaryControl, stretch, i18nStrings, ...rest } = props;
9
9
  const resource = useResourceContext();
10
+ const translate = useTranslate();
10
11
  const context = useFormFieldContext();
11
12
  const inputState = context ??
12
13
  useInput({
@@ -26,7 +27,15 @@ export const FormField = (props) => {
26
27
  const { id, fieldState: { isTouched, invalid, error }, formState: { isSubmitted }, isRequired, } = inputState;
27
28
  const errorToProcess = error?.message || error?.root?.message;
28
29
  const errorText = (isTouched || isSubmitted) && invalid && typeof errorToProcess === 'string' ? (_jsx(ValidationError, { error: errorToProcess })) : undefined;
29
- const content = (_jsx(CloudscapeFormField, { id: id, label: label === false ? undefined : (_jsx(FieldTitle, { label: label, source: source, resource: resource, isRequired: isRequired })), description: description, constraintText: constraintText, info: info, secondaryControl: secondaryControl, stretch: stretch, i18nStrings: i18nStrings, errorText: errorText, children: children }));
30
+ const finalConstraintText = React.useMemo(() => {
31
+ if (isRequired)
32
+ return constraintText;
33
+ const optionalLabel = `(${translate('optional')})`;
34
+ if (!constraintText)
35
+ return optionalLabel;
36
+ return (_jsxs(_Fragment, { children: [constraintText, " (", optionalLabel, ")"] }));
37
+ }, [isRequired, constraintText, translate]);
38
+ const content = (_jsx(CloudscapeFormField, { id: id, label: label === false ? undefined : (_jsx(FieldTitle, { label: label, source: source, resource: resource, isRequired: isRequired })), description: label === false ? undefined : description, constraintText: label === false ? undefined : finalConstraintText, info: info, secondaryControl: secondaryControl, stretch: stretch, i18nStrings: i18nStrings, errorText: errorText, children: children }));
30
39
  if (context) {
31
40
  return content;
32
41
  }
@@ -1,4 +1,4 @@
1
- import { UseInputValue } from '@strato-admin/core';
1
+ import { UseInputValue } from '@strato-admin/ra-core';
2
2
  export interface FormFieldContextValue extends UseInputValue {
3
3
  source?: string;
4
4
  }
@@ -1,6 +1,6 @@
1
1
  import { InputProps as CloudscapeInputProps } from '@cloudscape-design/components/input';
2
2
  import { InputProps } from './types';
3
- export interface NumberInputProps extends Omit<CloudscapeInputProps, 'onChange' | 'value' | 'onBlur' | 'type'>, InputProps {
3
+ export interface NumberInputProps extends InputProps, Pick<CloudscapeInputProps, 'placeholder' | 'disabled' | 'readOnly' | 'autoFocus' | 'step'> {
4
4
  type?: CloudscapeInputProps['type'];
5
5
  }
6
6
  export declare const NumberInput: (props: NumberInputProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useInput } from '@strato-admin/core';
2
+ import { useInput } from '@strato-admin/ra-core';
3
3
  import CloudscapeInput from '@cloudscape-design/components/input';
4
4
  import { FormField } from './FormField';
5
5
  import { FormFieldContext, useFormFieldContext } from './FormFieldContext';
6
6
  export const NumberInput = (props) => {
7
- const { label, source, defaultValue, validate, type = 'number', ...rest } = props;
7
+ const { label, source, defaultValue, validate, type = 'number', placeholder, disabled, readOnly, autoFocus, step, ...rest } = props;
8
8
  const context = useFormFieldContext();
9
9
  const inputState = context ??
10
10
  useInput({
@@ -18,7 +18,7 @@ export const NumberInput = (props) => {
18
18
  const floatValue = parseFloat(value);
19
19
  field.onChange(isNaN(floatValue) ? null : floatValue);
20
20
  };
21
- const inner = (_jsx(CloudscapeInput, { ...rest, ...field, id: id, type: type, value: field.value?.toString() || '', onChange: (event) => handleChange(event.detail.value), onBlur: () => field.onBlur() }));
21
+ const inner = (_jsx(CloudscapeInput, { ...field, id: id, type: type, placeholder: placeholder, disabled: disabled, readOnly: readOnly, autoFocus: autoFocus, step: step, value: field.value?.toString() || '', onChange: (event) => handleChange(event.detail.value), onBlur: () => field.onBlur() }));
22
22
  if (context) {
23
23
  return inner;
24
24
  }
@@ -1,3 +1,3 @@
1
- import { type ReferenceInputBaseProps } from '@strato-admin/core';
1
+ import { type ReferenceInputBaseProps } from '@strato-admin/ra-core';
2
2
  export declare const ReferenceInput: (props: ReferenceInputBaseProps) => import("react/jsx-runtime").JSX.Element;
3
3
  export default ReferenceInput;
@@ -1,25 +1,35 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React from 'react';
3
- import { ReferenceInputBase } from '@strato-admin/core';
4
- import { useFormFieldContext } from './FormFieldContext';
3
+ import { ReferenceInputBase, useInput } from '@strato-admin/ra-core';
4
+ import { FormField } from './FormField';
5
+ import { FormFieldContext, useFormFieldContext } from './FormFieldContext';
5
6
  import { AutocompleteInput } from './AutocompleteInput';
6
7
  export const ReferenceInput = (props) => {
7
- const { children, source: sourceProp, reference, ...rest } = props;
8
+ const { children, source: sourceProp, reference, isRequired, validate, defaultValue, label, ...rest } = props;
8
9
  const context = useFormFieldContext();
9
10
  // If we have a context, we use the source from it.
10
11
  const source = sourceProp || context?.source;
11
12
  if (!source) {
12
13
  throw new Error('ReferenceInput requires a source prop or a parent FormField Master');
13
14
  }
15
+ const inputState = context ??
16
+ useInput({
17
+ source,
18
+ defaultValue,
19
+ validate,
20
+ isRequired,
21
+ ...rest,
22
+ });
14
23
  const finalChildren = children || _jsx(AutocompleteInput, { source: source });
15
- const inner = (_jsx(ReferenceInputBase, { source: source, reference: reference, ...rest, children: React.isValidElement(finalChildren)
16
- ? React.cloneElement(finalChildren, {
17
- source,
18
- })
19
- : finalChildren }));
20
- // ReferenceInput is unique because it's a wrapper.
21
- // It doesn't use FormFieldContext for its state directly (ReferenceInputBase does),
22
- // but it needs to ensure its children can consume the state it provides via ReferenceInputBase.
23
- return inner;
24
+ const inner = (_jsx(ReferenceInputBase, { source: source, reference: reference, isRequired: isRequired, ...rest, children: _jsx(FormFieldContext.Provider, { value: inputState, children: React.isValidElement(finalChildren)
25
+ ? React.cloneElement(finalChildren, {
26
+ source,
27
+ isRequired,
28
+ })
29
+ : finalChildren }) }));
30
+ if (context) {
31
+ return inner;
32
+ }
33
+ return (_jsx(FormFieldContext.Provider, { value: inputState, children: _jsx(FormField, { ...props, children: inner }) }));
24
34
  };
25
35
  export default ReferenceInput;
@@ -1,6 +1,6 @@
1
1
  import { SelectProps as CloudscapeSelectProps } from '@cloudscape-design/components/select';
2
2
  import { InputProps } from './types';
3
- export interface SelectInputProps extends Omit<CloudscapeSelectProps, 'onChange' | 'selectedOption' | 'options' | 'onBlur'>, InputProps {
3
+ export interface SelectInputProps extends InputProps, Pick<CloudscapeSelectProps, 'filteringType' | 'placeholder' | 'disabled' | 'readOnly'> {
4
4
  choices?: Array<{
5
5
  id: string | number;
6
6
  [key: string]: any;
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React from 'react';
3
- import { useInput, useResourceContext, useChoicesContext, useGetRecordRepresentation, } from '@strato-admin/core';
3
+ import { useInput, useResourceContext, useChoicesContext, useGetRecordRepresentation } from '@strato-admin/ra-core';
4
4
  import CloudscapeSelect from '@cloudscape-design/components/select';
5
5
  import { FormField } from './FormField';
6
6
  import { FormFieldContext, useFormFieldContext } from './FormFieldContext';
7
7
  export const SelectInput = (props) => {
8
- const { label, source, defaultValue, validate, choices: choicesProp, emptyText = '-', ...rest } = props;
8
+ const { label, source, defaultValue, validate, choices: choicesProp, emptyText = '-', filteringType, placeholder, disabled, readOnly, ...rest } = props;
9
9
  const resource = useResourceContext();
10
10
  const { allChoices, isPending } = useChoicesContext(props);
11
11
  const getRecordRepresentation = useGetRecordRepresentation(resource);
@@ -35,7 +35,7 @@ export const SelectInput = (props) => {
35
35
  }
36
36
  return option.value === String(field.value);
37
37
  }) || null;
38
- const inner = (_jsx(CloudscapeSelect, { ...rest, id: id, options: options, selectedOption: selectedOption, statusType: isPending ? 'loading' : 'finished', expandToViewport: true, onChange: ({ detail }) => {
38
+ const inner = (_jsx(CloudscapeSelect, { id: id, filteringType: filteringType, placeholder: placeholder, disabled: disabled, readOnly: readOnly, options: options, selectedOption: selectedOption, statusType: isPending ? 'loading' : 'finished', expandToViewport: true, onChange: ({ detail }) => {
39
39
  const value = detail.selectedOption.value === '__EMPTY__' ? null : detail.selectedOption.value;
40
40
  field.onChange(value);
41
41
  }, onBlur: () => field.onBlur() }));
@@ -1,6 +1,6 @@
1
1
  import { SliderProps as CloudscapeSliderProps } from '@cloudscape-design/components/slider';
2
2
  import { InputProps } from './types';
3
- export interface SliderInputProps extends Omit<CloudscapeSliderProps, 'onChange' | 'value' | 'i18nStrings'>, InputProps {
3
+ export interface SliderInputProps extends InputProps, Partial<Pick<CloudscapeSliderProps, 'min' | 'max'>>, Pick<CloudscapeSliderProps, 'step' | 'disabled' | 'readOnly' | 'valueFormatter' | 'tickMarks' | 'referenceValues' | 'hideFillLine' | 'ariaLabel' | 'ariaDescription'> {
4
4
  }
5
5
  export declare const SliderInput: (props: SliderInputProps) => import("react/jsx-runtime").JSX.Element;
6
6
  export default SliderInput;
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useInput } from '@strato-admin/core';
2
+ import { useInput } from '@strato-admin/ra-core';
3
3
  import CloudscapeSlider from '@cloudscape-design/components/slider';
4
4
  import { FormField } from './FormField';
5
5
  import { FormFieldContext, useFormFieldContext } from './FormFieldContext';
6
6
  export const SliderInput = (props) => {
7
- const { label, source, defaultValue, validate, ...rest } = props;
7
+ const { label, source, defaultValue, validate, min, max, step, disabled, readOnly, valueFormatter, tickMarks, referenceValues, hideFillLine, ariaLabel, ariaDescription, ...rest } = props;
8
8
  const context = useFormFieldContext();
9
9
  const inputState = context ??
10
10
  useInput({
@@ -15,8 +15,8 @@ export const SliderInput = (props) => {
15
15
  });
16
16
  const { id, field } = inputState;
17
17
  // Cloudscape Slider requires a number value
18
- const value = typeof field.value === 'number' ? field.value : props.min ?? 0;
19
- const inner = (_jsx(CloudscapeSlider, { ...rest, id: id, value: value, onChange: (event) => field.onChange(event.detail.value) }));
18
+ const value = typeof field.value === 'number' ? field.value : (min ?? 0);
19
+ const inner = (_jsx(CloudscapeSlider, { id: id, min: min ?? 0, max: max ?? 100, step: step, disabled: disabled, readOnly: readOnly, valueFormatter: valueFormatter, tickMarks: tickMarks, referenceValues: referenceValues, hideFillLine: hideFillLine, ariaLabel: ariaLabel, ariaDescription: ariaDescription, value: value, onChange: (event) => field.onChange(event.detail.value) }));
20
20
  if (context) {
21
21
  return inner;
22
22
  }
@@ -1,6 +1,6 @@
1
1
  import { TextareaProps as CloudscapeTextareaProps } from '@cloudscape-design/components/textarea';
2
2
  import { InputProps } from './types';
3
- export interface TextAreaInputProps extends Omit<CloudscapeTextareaProps, 'onChange' | 'value' | 'onBlur'>, InputProps {
3
+ export interface TextAreaInputProps extends InputProps, Pick<CloudscapeTextareaProps, 'placeholder' | 'disabled' | 'readOnly' | 'rows' | 'autoFocus' | 'spellcheck'> {
4
4
  }
5
5
  export declare const TextAreaInput: (props: TextAreaInputProps) => import("react/jsx-runtime").JSX.Element;
6
6
  export default TextAreaInput;
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useInput } from '@strato-admin/core';
2
+ import { useInput } from '@strato-admin/ra-core';
3
3
  import CloudscapeTextarea from '@cloudscape-design/components/textarea';
4
4
  import { FormField } from './FormField';
5
5
  import { FormFieldContext, useFormFieldContext } from './FormFieldContext';
6
6
  export const TextAreaInput = (props) => {
7
- const { label, source, defaultValue, validate, ...rest } = props;
7
+ const { label, source, defaultValue, validate, placeholder, disabled, readOnly, rows, autoFocus, spellcheck, ...rest } = props;
8
8
  const context = useFormFieldContext();
9
9
  const inputState = context ??
10
10
  useInput({
@@ -14,7 +14,7 @@ export const TextAreaInput = (props) => {
14
14
  ...rest,
15
15
  });
16
16
  const { id, field } = inputState;
17
- const inner = (_jsx(CloudscapeTextarea, { ...rest, ...field, id: id, value: field.value || '', onChange: (event) => field.onChange(event.detail.value), onBlur: () => field.onBlur() }));
17
+ const inner = (_jsx(CloudscapeTextarea, { ...field, id: id, placeholder: placeholder, disabled: disabled, readOnly: readOnly, rows: rows, autoFocus: autoFocus, spellcheck: spellcheck, value: field.value || '', onChange: (event) => field.onChange(event.detail.value), onBlur: () => field.onBlur() }));
18
18
  if (context) {
19
19
  return inner;
20
20
  }
@@ -1,6 +1,6 @@
1
1
  import { InputProps as CloudscapeInputProps } from '@cloudscape-design/components/input';
2
2
  import { InputProps } from './types';
3
- export interface TextInputProps extends Omit<CloudscapeInputProps, 'onChange' | 'value' | 'onBlur' | 'type'>, InputProps {
3
+ export interface TextInputProps extends InputProps, Pick<CloudscapeInputProps, 'placeholder' | 'disabled' | 'readOnly' | 'autoFocus' | 'autoComplete' | 'spellcheck' | 'inputMode'> {
4
4
  type?: CloudscapeInputProps['type'];
5
5
  }
6
6
  export declare const TextInput: (props: TextInputProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,23 +1,17 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useInput } from '@strato-admin/core';
2
+ import { useInput } from '@strato-admin/ra-core';
3
3
  import CloudscapeInput from '@cloudscape-design/components/input';
4
4
  import { FormField } from './FormField';
5
5
  import { FormFieldContext, useFormFieldContext } from './FormFieldContext';
6
6
  export const TextInput = (props) => {
7
- const { label, source, defaultValue, validate, type = 'text', ...rest } = props;
7
+ const { label, source, defaultValue, validate, description, constraintText, info, secondaryControl, type = 'text', placeholder, disabled, readOnly, autoFocus, autoComplete, spellcheck, inputMode, } = props;
8
8
  const context = useFormFieldContext();
9
- const inputState = context ??
10
- useInput({
11
- source,
12
- defaultValue,
13
- validate,
14
- ...rest,
15
- });
16
- const { id, field } = inputState;
17
- const inner = (_jsx(CloudscapeInput, { ...rest, ...field, id: id, type: type, value: field.value || '', onChange: (event) => field.onChange(event.detail.value), onBlur: () => field.onBlur() }));
9
+ const inputState = context ?? useInput({ source, defaultValue, validate });
10
+ const { field } = inputState;
11
+ const inner = (_jsx(CloudscapeInput, { ...field, type: type, placeholder: placeholder, disabled: disabled, readOnly: readOnly, autoFocus: autoFocus, autoComplete: autoComplete, spellcheck: spellcheck, inputMode: inputMode, value: field.value || '', onChange: (event) => field.onChange(event.detail.value), onBlur: () => field.onBlur() }));
18
12
  if (context) {
19
13
  return inner;
20
14
  }
21
- return (_jsx(FormFieldContext.Provider, { value: inputState, children: _jsx(FormField, { ...props, children: inner }) }));
15
+ return (_jsx(FormFieldContext.Provider, { value: inputState, children: _jsx(FormField, { source: source, label: label, description: description, constraintText: constraintText, info: info, secondaryControl: secondaryControl, children: inner }) }));
22
16
  };
23
17
  export default TextInput;
@@ -1,8 +1,9 @@
1
1
  export * from './types';
2
+ export * from './BooleanInput';
2
3
  export * from './TextInput';
3
4
  export * from './TextAreaInput';
4
5
  export * from './NumberInput';
5
- export * from './AttributeEditor';
6
+ export * from './ArrayInput';
6
7
  export * from './SelectInput';
7
8
  export * from './AutocompleteInput';
8
9
  export * from './ReferenceInput';
@@ -1,8 +1,9 @@
1
1
  export * from './types';
2
+ export * from './BooleanInput';
2
3
  export * from './TextInput';
3
4
  export * from './TextAreaInput';
4
5
  export * from './NumberInput';
5
- export * from './AttributeEditor';
6
+ export * from './ArrayInput';
6
7
  export * from './SelectInput';
7
8
  export * from './AutocompleteInput';
8
9
  export * from './ReferenceInput';
@@ -1,6 +1,37 @@
1
- import { InputProps as InputPropsBase } from '@strato-admin/core';
1
+ import React from 'react';
2
+ import { InputProps as InputPropsBase, Validator } from '@strato-admin/ra-core';
2
3
  import { FormFieldProps as CloudscapeFormFieldProps } from '@cloudscape-design/components/form-field';
3
- export interface StratoInputProps<T = any> extends Omit<InputPropsBase<T>, 'label'>, Pick<CloudscapeFormFieldProps, 'description' | 'constraintText' | 'info' | 'secondaryControl' | 'stretch' | 'i18nStrings'> {
4
+ /**
5
+ * Common props shared by all Strato Admin input components.
6
+ */
7
+ export interface StratoCommonInputProps<T = any> {
8
+ /** The field name in the record. Used to read and write the value. */
9
+ source: string;
10
+ /** Override the auto-generated label. Pass `false` to hide the label entirely. */
4
11
  label?: string | false;
12
+ /** The initial value when no record value exists. */
13
+ defaultValue?: any;
14
+ /** Validation rule or array of rules. Use built-in validators (`required()`, `minLength()`, etc.) or provide a custom function. */
15
+ validate?: Validator | Validator[];
16
+ /** Transforms the record value before passing it to the input (record → input). */
17
+ format?: (value: T) => any;
18
+ /** Transforms the input value before saving to the record (input → record). */
19
+ parse?: (value: any) => T;
20
+ /** When `true`, the value is visible but cannot be changed. */
21
+ readOnly?: boolean;
22
+ /** When `true`, the input is non-interactive and grayed out. */
23
+ disabled?: boolean;
24
+ /** Helper text displayed below the label. */
25
+ description?: React.ReactNode;
26
+ /** Additional constraint text. Appended with "(optional)" when the field is not required. */
27
+ constraintText?: React.ReactNode;
28
+ /** Info link displayed next to the label (Cloudscape `info` slot). */
29
+ info?: React.ReactNode;
30
+ /** Secondary control displayed to the right of the input (Cloudscape `secondaryControl` slot). */
31
+ secondaryControl?: React.ReactNode;
32
+ /** When `true`, the form field stretches to fill its container width. */
33
+ stretch?: boolean;
34
+ }
35
+ export interface StratoInputProps<T = any> extends StratoCommonInputProps<T>, Omit<InputPropsBase<T>, 'label' | 'source' | 'defaultValue' | 'validate' | 'format' | 'parse' | 'readOnly' | 'disabled'>, Pick<CloudscapeFormFieldProps, 'i18nStrings'> {
5
36
  }
6
37
  export type InputProps<T = any> = StratoInputProps<T>;
@@ -2,9 +2,10 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
2
2
  import { useState } from 'react';
3
3
  import CloudscapeAppLayout from '@cloudscape-design/components/app-layout';
4
4
  import SideNavigation from '@cloudscape-design/components/side-navigation';
5
- import { useResourceDefinitions, useDefaultTitle, useGetResourceLabel } from '@strato-admin/core';
5
+ import { useResourceDefinitions, useDefaultTitle, useGetResourceLabel } from '@strato-admin/ra-core';
6
6
  import { useNavigate } from 'react-router-dom';
7
7
  import { TopNavigation } from './TopNavigation';
8
+ import { Notifications } from './Notifications';
8
9
  import ThemeManager from '../theme/ThemeManager';
9
10
  export const AppLayout = ({ children, header, title }) => {
10
11
  const resources = useResourceDefinitions();
@@ -13,7 +14,9 @@ export const AppLayout = ({ children, header, title }) => {
13
14
  const defaultTitle = useDefaultTitle();
14
15
  const [navigationOpen, setNavigationOpen] = useState(true);
15
16
  const appTitle = title ?? (typeof defaultTitle === 'string' ? defaultTitle : '');
16
- const items = Object.values(resources).map((resource) => ({
17
+ const items = Object.values(resources)
18
+ .filter((resource) => resource.hasList)
19
+ .map((resource) => ({
17
20
  type: 'link',
18
21
  text: getResourceLabel(resource.name),
19
22
  href: `/${resource.name}`,
@@ -33,6 +36,6 @@ export const AppLayout = ({ children, header, title }) => {
33
36
  event.preventDefault();
34
37
  navigate(event.detail.href);
35
38
  }
36
- } }), content: _jsx("div", { children: children }) })] }));
39
+ } }), notifications: _jsx(Notifications, {}), content: _jsx("div", { children: children }) })] }));
37
40
  };
38
41
  export default AppLayout;
@@ -0,0 +1 @@
1
+ export declare const Notifications: () => import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,51 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useRef } from 'react';
3
+ import Flashbar from '@cloudscape-design/components/flashbar';
4
+ import { useNotificationContext, useTranslate } from '@strato-admin/ra-core';
5
+ const DEFAULT_AUTO_HIDE_MS = null;
6
+ let idCounter = 0;
7
+ const stableIds = new WeakMap();
8
+ const getStableId = (obj) => {
9
+ if (!stableIds.has(obj))
10
+ stableIds.set(obj, String(++idCounter));
11
+ return stableIds.get(obj);
12
+ };
13
+ export const Notifications = () => {
14
+ const { notifications, setNotifications } = useNotificationContext();
15
+ const translate = useTranslate();
16
+ const timers = useRef(new Map());
17
+ const dismiss = useCallback((notification) => {
18
+ const id = getStableId(notification);
19
+ clearTimeout(timers.current.get(id));
20
+ timers.current.delete(id);
21
+ setNotifications((prev) => prev.filter((n) => n !== notification));
22
+ }, [setNotifications]);
23
+ useEffect(() => {
24
+ notifications.forEach((notification) => {
25
+ const id = getStableId(notification);
26
+ if (timers.current.has(id))
27
+ return;
28
+ const ms = notification.notificationOptions?.autoHideDuration ?? DEFAULT_AUTO_HIDE_MS;
29
+ if (ms === null)
30
+ return;
31
+ timers.current.set(id, setTimeout(() => dismiss(notification), ms));
32
+ });
33
+ return () => {
34
+ timers.current.forEach((timer) => clearTimeout(timer));
35
+ timers.current.clear();
36
+ };
37
+ }, [notifications, dismiss]);
38
+ if (notifications.length === 0)
39
+ return null;
40
+ const items = notifications.map((notification) => {
41
+ const { message, type, notificationOptions } = notification;
42
+ return {
43
+ id: getStableId(notification),
44
+ type,
45
+ content: typeof message === 'string' ? translate(message, notificationOptions?.messageArgs) : message,
46
+ dismissible: true,
47
+ onDismiss: () => dismiss(notification),
48
+ };
49
+ });
50
+ return _jsx(Flashbar, { items: items });
51
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Default component to display when the admin has no resources.
3
+ * This is a Cloudscape-themed replacement for the default react-admin Ready component.
4
+ */
5
+ export declare const Ready: () => import("react/jsx-runtime").JSX.Element;
6
+ export default Ready;