@strato-admin/cloudscape 0.1.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 (255) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/dist/Admin.d.ts +17 -0
  4. package/dist/Admin.js +69 -0
  5. package/dist/RecordLink.d.ts +9 -0
  6. package/dist/RecordLink.js +43 -0
  7. package/dist/__mocks__/strato-core.js +50 -0
  8. package/dist/__mocks__to__delete/strato-core.js +50 -0
  9. package/dist/button/BulkDeleteButton.d.ts +7 -0
  10. package/dist/button/BulkDeleteButton.js +17 -0
  11. package/dist/button/Button.d.ts +6 -0
  12. package/dist/button/Button.js +6 -0
  13. package/dist/button/CreateButton.d.ts +6 -0
  14. package/dist/button/CreateButton.js +24 -0
  15. package/dist/button/EditButton.d.ts +8 -0
  16. package/dist/button/EditButton.js +24 -0
  17. package/dist/button/SaveButton.d.ts +6 -0
  18. package/dist/button/SaveButton.js +8 -0
  19. package/dist/button/index.d.ts +5 -0
  20. package/dist/button/index.js +5 -0
  21. package/dist/collection-hooks/index.d.ts +2 -0
  22. package/dist/collection-hooks/index.js +2 -0
  23. package/dist/collection-hooks/interfaces.d.ts +93 -0
  24. package/dist/collection-hooks/interfaces.js +1 -0
  25. package/dist/collection-hooks/useCollection.d.ts +3 -0
  26. package/dist/collection-hooks/useCollection.js +102 -0
  27. package/dist/create/Create.d.ts +40 -0
  28. package/dist/create/Create.js +34 -0
  29. package/dist/create/CreateHeader.d.ts +7 -0
  30. package/dist/create/CreateHeader.js +18 -0
  31. package/dist/create/index.d.ts +2 -0
  32. package/dist/create/index.js +2 -0
  33. package/dist/detail/KeyValuePairs.d.ts +36 -0
  34. package/dist/detail/KeyValuePairs.js +58 -0
  35. package/dist/detail/Show.d.ts +39 -0
  36. package/dist/detail/Show.js +40 -0
  37. package/dist/detail/ShowHeader.d.ts +7 -0
  38. package/dist/detail/ShowHeader.js +19 -0
  39. package/dist/detail/index.d.ts +3 -0
  40. package/dist/detail/index.js +3 -0
  41. package/dist/edit/Edit.d.ts +42 -0
  42. package/dist/edit/Edit.js +38 -0
  43. package/dist/edit/EditHeader.d.ts +7 -0
  44. package/dist/edit/EditHeader.js +18 -0
  45. package/dist/edit/index.d.ts +2 -0
  46. package/dist/edit/index.js +2 -0
  47. package/dist/field/ArrayField.d.ts +29 -0
  48. package/dist/field/ArrayField.js +30 -0
  49. package/dist/field/BadgeField.d.ts +12 -0
  50. package/dist/field/BadgeField.js +15 -0
  51. package/dist/field/BooleanField.d.ts +18 -0
  52. package/dist/field/BooleanField.js +14 -0
  53. package/dist/field/CurrencyField.d.ts +19 -0
  54. package/dist/field/CurrencyField.js +23 -0
  55. package/dist/field/DateField.d.ts +14 -0
  56. package/dist/field/DateField.js +17 -0
  57. package/dist/field/IdField.d.ts +17 -0
  58. package/dist/field/IdField.js +21 -0
  59. package/dist/field/NumberField.d.ts +14 -0
  60. package/dist/field/NumberField.js +18 -0
  61. package/dist/field/ReferenceField.d.ts +16 -0
  62. package/dist/field/ReferenceField.js +23 -0
  63. package/dist/field/ReferenceManyField.d.ts +55 -0
  64. package/dist/field/ReferenceManyField.js +19 -0
  65. package/dist/field/StatusIndicatorField.d.ts +56 -0
  66. package/dist/field/StatusIndicatorField.js +48 -0
  67. package/dist/field/TextField.d.ts +5 -0
  68. package/dist/field/TextField.js +11 -0
  69. package/dist/field/index.d.ts +23 -0
  70. package/dist/field/index.js +23 -0
  71. package/dist/field/types.d.ts +56 -0
  72. package/dist/field/types.js +1 -0
  73. package/dist/form/Form.d.ts +13 -0
  74. package/dist/form/Form.js +33 -0
  75. package/dist/form/index.d.ts +2 -0
  76. package/dist/form/index.js +2 -0
  77. package/dist/index.d.ts +22 -0
  78. package/dist/index.js +22 -0
  79. package/dist/input/AttributeEditor.d.ts +25 -0
  80. package/dist/input/AttributeEditor.js +80 -0
  81. package/dist/input/AutocompleteInput.d.ts +10 -0
  82. package/dist/input/AutocompleteInput.js +67 -0
  83. package/dist/input/FieldTitle.d.ts +8 -0
  84. package/dist/input/FieldTitle.js +29 -0
  85. package/dist/input/FormField.d.ts +7 -0
  86. package/dist/input/FormField.js +35 -0
  87. package/dist/input/FormFieldContext.d.ts +6 -0
  88. package/dist/input/FormFieldContext.js +3 -0
  89. package/dist/input/NumberInput.d.ts +7 -0
  90. package/dist/input/NumberInput.js +27 -0
  91. package/dist/input/ReferenceInput.d.ts +3 -0
  92. package/dist/input/ReferenceInput.js +25 -0
  93. package/dist/input/SelectInput.d.ts +15 -0
  94. package/dist/input/SelectInput.js +47 -0
  95. package/dist/input/SliderInput.d.ts +6 -0
  96. package/dist/input/SliderInput.js +25 -0
  97. package/dist/input/TextAreaInput.d.ts +6 -0
  98. package/dist/input/TextAreaInput.js +23 -0
  99. package/dist/input/TextInput.d.ts +7 -0
  100. package/dist/input/TextInput.js +23 -0
  101. package/dist/input/index.d.ts +11 -0
  102. package/dist/input/index.js +11 -0
  103. package/dist/input/types.d.ts +6 -0
  104. package/dist/input/types.js +1 -0
  105. package/dist/layout/AppLayout.d.ts +8 -0
  106. package/dist/layout/AppLayout.js +38 -0
  107. package/dist/layout/TopNavigation.d.ts +6 -0
  108. package/dist/layout/TopNavigation.js +53 -0
  109. package/dist/layout/index.d.ts +2 -0
  110. package/dist/layout/index.js +2 -0
  111. package/dist/list/Cards.d.ts +11 -0
  112. package/dist/list/Cards.js +27 -0
  113. package/dist/list/List.d.ts +43 -0
  114. package/dist/list/List.js +28 -0
  115. package/dist/list/Table.d.ts +112 -0
  116. package/dist/list/Table.examples.d.ts +1 -0
  117. package/dist/list/Table.examples.js +3 -0
  118. package/dist/list/Table.js +218 -0
  119. package/dist/list/TableHeader.d.ts +7 -0
  120. package/dist/list/TableHeader.js +22 -0
  121. package/dist/list/index.d.ts +4 -0
  122. package/dist/list/index.js +4 -0
  123. package/dist/preferences/index.d.ts +0 -0
  124. package/dist/preferences/index.js +1 -0
  125. package/dist/theme/ThemeManager.d.ts +2 -0
  126. package/dist/theme/ThemeManager.js +11 -0
  127. package/dist/theme/index.d.ts +2 -0
  128. package/dist/theme/index.js +2 -0
  129. package/package.json +73 -0
  130. package/src/Admin.test.tsx +32 -0
  131. package/src/Admin.tsx +123 -0
  132. package/src/RecordLink.stories.tsx +56 -0
  133. package/src/RecordLink.tsx +67 -0
  134. package/src/__mocks__/strato-core.tsx +52 -0
  135. package/src/button/BulkDeleteButton.stories.tsx +59 -0
  136. package/src/button/BulkDeleteButton.test.tsx +64 -0
  137. package/src/button/BulkDeleteButton.tsx +41 -0
  138. package/src/button/Button.stories.tsx +31 -0
  139. package/src/button/Button.tsx +12 -0
  140. package/src/button/CreateButton.stories.tsx +42 -0
  141. package/src/button/CreateButton.tsx +38 -0
  142. package/src/button/EditButton.stories.tsx +29 -0
  143. package/src/button/EditButton.tsx +38 -0
  144. package/src/button/SaveButton.stories.tsx +35 -0
  145. package/src/button/SaveButton.tsx +19 -0
  146. package/src/button/index.ts +5 -0
  147. package/src/collection-hooks/index.ts +2 -0
  148. package/src/collection-hooks/interfaces.ts +80 -0
  149. package/src/collection-hooks/useCollection.test.ts +413 -0
  150. package/src/collection-hooks/useCollection.ts +125 -0
  151. package/src/create/Create.test.tsx +63 -0
  152. package/src/create/Create.tsx +93 -0
  153. package/src/create/CreateHeader.tsx +34 -0
  154. package/src/create/index.ts +2 -0
  155. package/src/detail/KeyValuePairs.test.tsx +98 -0
  156. package/src/detail/KeyValuePairs.tsx +107 -0
  157. package/src/detail/Show.test.tsx +96 -0
  158. package/src/detail/Show.tsx +104 -0
  159. package/src/detail/ShowHeader.test.tsx +80 -0
  160. package/src/detail/ShowHeader.tsx +35 -0
  161. package/src/detail/index.ts +3 -0
  162. package/src/edit/Edit.test.tsx +91 -0
  163. package/src/edit/Edit.tsx +102 -0
  164. package/src/edit/EditHeader.tsx +34 -0
  165. package/src/edit/index.ts +2 -0
  166. package/src/field/ArrayField.tsx +51 -0
  167. package/src/field/BadgeField.tsx +33 -0
  168. package/src/field/BooleanField.stories.tsx +56 -0
  169. package/src/field/BooleanField.test.tsx +63 -0
  170. package/src/field/BooleanField.tsx +42 -0
  171. package/src/field/CurrencyField.stories.tsx +67 -0
  172. package/src/field/CurrencyField.tsx +45 -0
  173. package/src/field/DateField.stories.tsx +67 -0
  174. package/src/field/DateField.tsx +33 -0
  175. package/src/field/IdField.test.tsx +88 -0
  176. package/src/field/IdField.tsx +40 -0
  177. package/src/field/NumberField.stories.tsx +75 -0
  178. package/src/field/NumberField.tsx +35 -0
  179. package/src/field/ReferenceField.test.tsx +88 -0
  180. package/src/field/ReferenceField.tsx +64 -0
  181. package/src/field/ReferenceManyField.test.tsx +41 -0
  182. package/src/field/ReferenceManyField.tsx +73 -0
  183. package/src/field/StatusIndicatorField.stories.tsx +93 -0
  184. package/src/field/StatusIndicatorField.test.tsx +143 -0
  185. package/src/field/StatusIndicatorField.tsx +119 -0
  186. package/src/field/TextField.stories.tsx +45 -0
  187. package/src/field/TextField.tsx +17 -0
  188. package/src/field/index.ts +23 -0
  189. package/src/field/types.ts +58 -0
  190. package/src/form/Form.test.tsx +55 -0
  191. package/src/form/Form.tsx +66 -0
  192. package/src/form/index.ts +2 -0
  193. package/src/index.ts +25 -0
  194. package/src/input/AttributeEditor.test.tsx +147 -0
  195. package/src/input/AttributeEditor.tsx +185 -0
  196. package/src/input/AutocompleteInput.test.tsx +178 -0
  197. package/src/input/AutocompleteInput.tsx +116 -0
  198. package/src/input/FieldTitle.tsx +53 -0
  199. package/src/input/FormField.tsx +87 -0
  200. package/src/input/FormFieldContext.ts +9 -0
  201. package/src/input/NumberInput.tsx +56 -0
  202. package/src/input/ReferenceInput.test.tsx +35 -0
  203. package/src/input/ReferenceInput.tsx +36 -0
  204. package/src/input/SelectInput.tsx +91 -0
  205. package/src/input/SliderInput.test.tsx +103 -0
  206. package/src/input/SliderInput.tsx +49 -0
  207. package/src/input/TextAreaInput.tsx +48 -0
  208. package/src/input/TextInput.test.tsx +91 -0
  209. package/src/input/TextInput.tsx +51 -0
  210. package/src/input/index.ts +11 -0
  211. package/src/input/types.ts +14 -0
  212. package/src/layout/AppLayout.test.tsx +87 -0
  213. package/src/layout/AppLayout.tsx +60 -0
  214. package/src/layout/TopNavigation.test.tsx +78 -0
  215. package/src/layout/TopNavigation.tsx +84 -0
  216. package/src/layout/index.ts +2 -0
  217. package/src/list/Cards.tsx +58 -0
  218. package/src/list/List.tsx +76 -0
  219. package/src/list/Table.examples.tsx +11 -0
  220. package/src/list/Table.stories.tsx +73 -0
  221. package/src/list/Table.test.tsx +255 -0
  222. package/src/list/Table.tsx +438 -0
  223. package/src/list/TableHeader.test.tsx +114 -0
  224. package/src/list/TableHeader.tsx +44 -0
  225. package/src/list/index.ts +4 -0
  226. package/src/preferences/index.ts +0 -0
  227. package/src/stories/Button.stories.ts +54 -0
  228. package/src/stories/Button.tsx +31 -0
  229. package/src/stories/Configure.mdx +369 -0
  230. package/src/stories/Header.stories.ts +34 -0
  231. package/src/stories/Header.tsx +47 -0
  232. package/src/stories/Page.stories.ts +33 -0
  233. package/src/stories/Page.tsx +71 -0
  234. package/src/stories/RaStoryDecorator.tsx +38 -0
  235. package/src/stories/assets/accessibility.png +0 -0
  236. package/src/stories/assets/accessibility.svg +1 -0
  237. package/src/stories/assets/addon-library.png +0 -0
  238. package/src/stories/assets/assets.png +0 -0
  239. package/src/stories/assets/avif-test-image.avif +0 -0
  240. package/src/stories/assets/context.png +0 -0
  241. package/src/stories/assets/discord.svg +1 -0
  242. package/src/stories/assets/docs.png +0 -0
  243. package/src/stories/assets/figma-plugin.png +0 -0
  244. package/src/stories/assets/github.svg +1 -0
  245. package/src/stories/assets/share.png +0 -0
  246. package/src/stories/assets/styling.png +0 -0
  247. package/src/stories/assets/testing.png +0 -0
  248. package/src/stories/assets/theming.png +0 -0
  249. package/src/stories/assets/tutorials.svg +1 -0
  250. package/src/stories/assets/youtube.svg +1 -0
  251. package/src/stories/button.css +30 -0
  252. package/src/stories/header.css +32 -0
  253. package/src/stories/page.css +68 -0
  254. package/src/theme/ThemeManager.tsx +15 -0
  255. package/src/theme/index.ts +2 -0
@@ -0,0 +1,17 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useFieldValue, useRecordContext, useLocale } from '@strato-admin/core';
3
+ import RecordLink from '../RecordLink';
4
+ const DateField = (props) => {
5
+ const { source, record: recordProp, emptyText, options, locales, link } = props;
6
+ const record = useRecordContext({ record: recordProp });
7
+ const value = useFieldValue({ source: source, record });
8
+ const currentLocale = useLocale();
9
+ const hasValue = value !== null && value !== undefined && value !== '';
10
+ if (!hasValue) {
11
+ return _jsx(_Fragment, { children: emptyText ?? null });
12
+ }
13
+ const dateValue = value instanceof Date ? value : new Date(value);
14
+ const formattedValue = new Intl.DateTimeFormat(locales || currentLocale, options).format(dateValue);
15
+ return _jsx(RecordLink, { link: link, children: formattedValue });
16
+ };
17
+ export default DateField;
@@ -0,0 +1,17 @@
1
+ import { type RaRecord } from '@strato-admin/core';
2
+ import { type TextFieldProps } from './TextField';
3
+ export type IdFieldProps<RecordType extends RaRecord = RaRecord> = TextFieldProps<RecordType>;
4
+ /**
5
+ * A field that displays the record's ID.
6
+ *
7
+ * Defaults to:
8
+ * - source="id"
9
+ * - input={false} (hidden in forms)
10
+ * - link="show" if the resource has a show page
11
+ *
12
+ * @example
13
+ * <IdField />
14
+ * <IdField source="identifier" />
15
+ */
16
+ declare const IdField: <RecordType extends RaRecord = RaRecord>(props: IdFieldProps<RecordType>) => import("react/jsx-runtime").JSX.Element;
17
+ export default IdField;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useResourceDefinition } from '@strato-admin/core';
3
+ import TextField from './TextField';
4
+ /**
5
+ * A field that displays the record's ID.
6
+ *
7
+ * Defaults to:
8
+ * - source="id"
9
+ * - input={false} (hidden in forms)
10
+ * - link="show" if the resource has a show page
11
+ *
12
+ * @example
13
+ * <IdField />
14
+ * <IdField source="identifier" />
15
+ */
16
+ const IdField = (props) => {
17
+ const { hasShow } = useResourceDefinition(props);
18
+ const { source = 'id', link = hasShow ? 'show' : undefined, input = false, ...rest } = props;
19
+ return (_jsx(TextField, { source: source, link: link, input: input, ...rest }));
20
+ };
21
+ export default IdField;
@@ -0,0 +1,14 @@
1
+ import { type RaRecord } from '@strato-admin/core';
2
+ import { type FieldProps } from './types';
3
+ export type NumberFieldProps<RecordType extends RaRecord = RaRecord> = FieldProps<RecordType> & {
4
+ /**
5
+ * Options for Intl.NumberFormat.
6
+ */
7
+ options?: Intl.NumberFormatOptions;
8
+ /**
9
+ * Locale(s) to use for formatting. Defaults to the current app locale.
10
+ */
11
+ locales?: string | string[];
12
+ };
13
+ declare const NumberField: <RecordType extends RaRecord = RaRecord>(props: NumberFieldProps<RecordType>) => import("react/jsx-runtime").JSX.Element;
14
+ export default NumberField;
@@ -0,0 +1,18 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useFieldValue, useRecordContext, useLocale } from '@strato-admin/core';
3
+ import RecordLink from '../RecordLink';
4
+ const NumberField = (props) => {
5
+ const { source, record: recordProp, emptyText, options, locales, link } = props;
6
+ const record = useRecordContext({ record: recordProp });
7
+ const value = useFieldValue({ source: source, record });
8
+ const currentLocale = useLocale();
9
+ const hasValue = value !== null && value !== undefined && value !== '';
10
+ if (!hasValue) {
11
+ return _jsx(_Fragment, { children: emptyText ?? null });
12
+ }
13
+ const numberValue = typeof value === 'string' ? parseFloat(value) : value;
14
+ const formattedValue = new Intl.NumberFormat(locales || currentLocale, options).format(numberValue);
15
+ return _jsx(RecordLink, { link: link, children: formattedValue });
16
+ };
17
+ NumberField.isNumberColumn = true;
18
+ export default NumberField;
@@ -0,0 +1,16 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type RaRecord } from '@strato-admin/core';
3
+ import { type FieldProps } from './types';
4
+ export type ReferenceFieldProps<RecordType extends RaRecord = RaRecord> = FieldProps<RecordType> & {
5
+ /**
6
+ * The resource name that this field refers to.
7
+ */
8
+ reference: string;
9
+ /**
10
+ * Optional custom representation of the related record. If not provided,
11
+ * the recordRepresentation of the referenced resource will be used.
12
+ */
13
+ children?: ReactNode;
14
+ };
15
+ declare const ReferenceField: <RecordType extends RaRecord = RaRecord>(props: ReferenceFieldProps<RecordType>) => import("react/jsx-runtime").JSX.Element | null;
16
+ export default ReferenceField;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { ReferenceFieldBase, useRecordContext, useGetRecordRepresentation, } from '@strato-admin/core';
3
+ import RecordLink from '../RecordLink';
4
+ const ReferenceField = (props) => {
5
+ const { source, reference, children, emptyText, record, link } = props;
6
+ if (!source) {
7
+ return null; // Or some fallback
8
+ }
9
+ return (_jsx(ReferenceFieldBase, { source: source, reference: reference, record: record, empty: _jsx(_Fragment, { children: emptyText ?? null }), children: _jsx(ReferenceFieldValue, { emptyText: emptyText, link: link, reference: reference, children: children }) }));
10
+ };
11
+ const ReferenceFieldValue = ({ children, emptyText, link, reference }) => {
12
+ const record = useRecordContext();
13
+ const getRecordRepresentation = useGetRecordRepresentation();
14
+ if (!record) {
15
+ return _jsx(_Fragment, { children: emptyText ?? null });
16
+ }
17
+ if (children) {
18
+ return (_jsx(RecordLink, { link: link, resource: reference, children: children }));
19
+ }
20
+ const representation = getRecordRepresentation(record);
21
+ return (_jsx(RecordLink, { link: link, resource: reference, children: representation ? String(representation) : (emptyText ?? null) }));
22
+ };
23
+ export default ReferenceField;
@@ -0,0 +1,55 @@
1
+ import { ReactNode } from 'react';
2
+ import { type RaRecord } from '@strato-admin/core';
3
+ import { type FieldProps } from './types';
4
+ export interface ReferenceManyFieldProps<RecordType extends RaRecord = RaRecord, ReferenceRecordType extends RaRecord = RaRecord> extends FieldProps<RecordType> {
5
+ children?: ReactNode;
6
+ reference: string;
7
+ target: string;
8
+ filter?: any;
9
+ sort?: {
10
+ field: string;
11
+ order: 'ASC' | 'DESC';
12
+ };
13
+ perPage?: number;
14
+ page?: number;
15
+ fieldSchema?: ReactNode;
16
+ /**
17
+ * Element to display during loading.
18
+ */
19
+ loading?: ReactNode;
20
+ /**
21
+ * Element to display if there's no data.
22
+ */
23
+ empty?: ReactNode;
24
+ /**
25
+ * Element to display if there's an error.
26
+ */
27
+ error?: ReactNode;
28
+ /**
29
+ * Element to display if the application is offline.
30
+ */
31
+ offline?: ReactNode;
32
+ /**
33
+ * Debounce time for filtering.
34
+ */
35
+ debounce?: number;
36
+ /**
37
+ * Whether to synchronize the list with the URL.
38
+ * @default false
39
+ */
40
+ synchronizeWithLocation?: boolean;
41
+ }
42
+ /**
43
+ * Render related records to the current one.
44
+ *
45
+ * @example
46
+ * <ReferenceManyField reference="comments" target="post_id">
47
+ * <Table title="Comments">
48
+ * <Table.Column source="id" />
49
+ * <Table.Column source="body" />
50
+ * <Table.Column source="created_at" />
51
+ * </Table>
52
+ * </ReferenceManyField>
53
+ */
54
+ export declare const ReferenceManyField: <RecordType extends RaRecord = RaRecord, ReferenceRecordType extends RaRecord = RaRecord>(props: ReferenceManyFieldProps<RecordType, ReferenceRecordType>) => import("react/jsx-runtime").JSX.Element;
55
+ export default ReferenceManyField;
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ReferenceManyFieldBase, ResourceSchemaProvider } from '@strato-admin/core';
3
+ /**
4
+ * Render related records to the current one.
5
+ *
6
+ * @example
7
+ * <ReferenceManyField reference="comments" target="post_id">
8
+ * <Table title="Comments">
9
+ * <Table.Column source="id" />
10
+ * <Table.Column source="body" />
11
+ * <Table.Column source="created_at" />
12
+ * </Table>
13
+ * </ReferenceManyField>
14
+ */
15
+ export const ReferenceManyField = (props) => {
16
+ const { children, reference, fieldSchema, ...rest } = props;
17
+ return (_jsx(ReferenceManyFieldBase, { reference: reference, ...rest, children: _jsx(ResourceSchemaProvider, { resource: reference, fieldSchema: fieldSchema, children: children }) }));
18
+ };
19
+ export default ReferenceManyField;
@@ -0,0 +1,56 @@
1
+ import { type StatusIndicatorProps } from '@cloudscape-design/components/status-indicator';
2
+ import React from 'react';
3
+ import { type RaRecord } from '@strato-admin/core';
4
+ import { type FieldProps } from './types';
5
+ export interface StatusIndicatorLabelProps {
6
+ /**
7
+ * The value to match against the field's value.
8
+ */
9
+ value: any;
10
+ /**
11
+ * The type of the status indicator for this value.
12
+ */
13
+ type: StatusIndicatorProps.Type;
14
+ /**
15
+ * Color override for the status indicator for this value.
16
+ */
17
+ color?: StatusIndicatorProps.Color;
18
+ /**
19
+ * The label to display. If not provided, the value will be used.
20
+ */
21
+ label?: React.ReactNode;
22
+ }
23
+ /**
24
+ * A declarative way to define status indicator mapping.
25
+ */
26
+ export declare const StatusIndicatorLabel: (_: StatusIndicatorLabelProps) => null;
27
+ export interface StatusIndicatorFieldProps<RecordType extends RaRecord = RaRecord> extends FieldProps<RecordType> {
28
+ /**
29
+ * The type of the status indicator.
30
+ * If provided as a string, it will be used for all values.
31
+ * If provided as a function, it will be called with the field value and the record.
32
+ * @default "info"
33
+ */
34
+ type?: StatusIndicatorProps.Type | ((value: any, record: RecordType) => StatusIndicatorProps.Type);
35
+ /**
36
+ * A mapping from field values to status indicator types.
37
+ */
38
+ mapping?: Record<string | number, StatusIndicatorProps.Type>;
39
+ /**
40
+ * Icon aria label for screen readers.
41
+ */
42
+ iconAriaLabel?: string;
43
+ /**
44
+ * Color override for the status indicator.
45
+ */
46
+ colorOverride?: StatusIndicatorProps.Color;
47
+ /**
48
+ * Declarative mapping using StatusIndicatorLabel children.
49
+ */
50
+ children?: React.ReactNode;
51
+ }
52
+ declare const StatusIndicatorField: {
53
+ <RecordType extends RaRecord = RaRecord<import("@strato-admin/ra-core").Identifier>>(props: StatusIndicatorFieldProps<RecordType>): import("react/jsx-runtime").JSX.Element;
54
+ Label: (_: StatusIndicatorLabelProps) => null;
55
+ };
56
+ export default StatusIndicatorField;
@@ -0,0 +1,48 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import StatusIndicator from '@cloudscape-design/components/status-indicator';
3
+ import React from 'react';
4
+ import { useFieldValue, useRecordContext, useTranslate } from '@strato-admin/core';
5
+ import RecordLink from '../RecordLink';
6
+ /**
7
+ * A declarative way to define status indicator mapping.
8
+ */
9
+ export const StatusIndicatorLabel = (_) => null;
10
+ const StatusIndicatorField = (props) => {
11
+ const { source, record: recordProp, emptyText, link, type, mapping, iconAriaLabel, colorOverride, children, } = props;
12
+ const record = useRecordContext({ record: recordProp });
13
+ const value = useFieldValue({ source: source, record });
14
+ const translate = useTranslate();
15
+ const hasValue = value !== null && value !== undefined && value !== '';
16
+ if (!hasValue) {
17
+ return _jsx(_Fragment, { children: emptyText ?? null });
18
+ }
19
+ // 1. Try to find mapping from children
20
+ const childrenArray = React.Children.toArray(children);
21
+ const matchingLabel = childrenArray.find((child) => child.props?.value === value);
22
+ let statusType = 'info';
23
+ let finalColorOverride = colorOverride;
24
+ let label = String(value);
25
+ if (matchingLabel) {
26
+ statusType = matchingLabel.props.type;
27
+ if (matchingLabel.props.color) {
28
+ finalColorOverride = matchingLabel.props.color;
29
+ }
30
+ if (matchingLabel.props.label) {
31
+ label = typeof matchingLabel.props.label === 'string'
32
+ ? translate(matchingLabel.props.label)
33
+ : matchingLabel.props.label;
34
+ }
35
+ }
36
+ else if (typeof type === 'function') {
37
+ statusType = type(value, record);
38
+ }
39
+ else if (type) {
40
+ statusType = type;
41
+ }
42
+ else if (mapping && value in mapping) {
43
+ statusType = mapping[value];
44
+ }
45
+ return (_jsx(RecordLink, { link: link, children: _jsx(StatusIndicator, { type: statusType, iconAriaLabel: iconAriaLabel, colorOverride: finalColorOverride, children: label }) }));
46
+ };
47
+ StatusIndicatorField.Label = StatusIndicatorLabel;
48
+ export default StatusIndicatorField;
@@ -0,0 +1,5 @@
1
+ import { type RaRecord } from '@strato-admin/core';
2
+ import { type FieldProps } from './types';
3
+ export type TextFieldProps<RecordType extends RaRecord = RaRecord> = FieldProps<RecordType>;
4
+ declare const TextField: <RecordType extends RaRecord = RaRecord>(props: TextFieldProps<RecordType>) => import("react/jsx-runtime").JSX.Element;
5
+ export default TextField;
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useFieldValue, useRecordContext } from '@strato-admin/core';
3
+ import RecordLink from '../RecordLink';
4
+ const TextField = (props) => {
5
+ const { source, record: recordProp, emptyText, link } = props;
6
+ const record = useRecordContext({ record: recordProp });
7
+ const value = useFieldValue({ source: source, record });
8
+ const hasValue = value !== null && value !== undefined && value !== '';
9
+ return _jsx(RecordLink, { link: link, children: hasValue ? String(value) : (emptyText ?? null) });
10
+ };
11
+ export default TextField;
@@ -0,0 +1,23 @@
1
+ export * from './types';
2
+ export { default as StatusIndicatorField } from './StatusIndicatorField';
3
+ export * from './StatusIndicatorField';
4
+ export { default as TextField } from './TextField';
5
+ export { default as IdField } from './IdField';
6
+ export { default as NumberField } from './NumberField';
7
+ export { default as CurrencyField } from './CurrencyField';
8
+ export { default as DateField } from './DateField';
9
+ export { default as BooleanField } from './BooleanField';
10
+ export { default as BadgeField } from './BadgeField';
11
+ export { default as ReferenceField } from './ReferenceField';
12
+ export { default as ReferenceManyField } from './ReferenceManyField';
13
+ export { default as ArrayField } from './ArrayField';
14
+ export * from './TextField';
15
+ export * from './IdField';
16
+ export * from './NumberField';
17
+ export * from './DateField';
18
+ export * from './BooleanField';
19
+ export * from './BadgeField';
20
+ export * from './ReferenceField';
21
+ export * from './ReferenceManyField';
22
+ export * from './ArrayField';
23
+ export * from './CurrencyField';
@@ -0,0 +1,23 @@
1
+ export * from './types';
2
+ export { default as StatusIndicatorField } from './StatusIndicatorField';
3
+ export * from './StatusIndicatorField';
4
+ export { default as TextField } from './TextField';
5
+ export { default as IdField } from './IdField';
6
+ export { default as NumberField } from './NumberField';
7
+ export { default as CurrencyField } from './CurrencyField';
8
+ export { default as DateField } from './DateField';
9
+ export { default as BooleanField } from './BooleanField';
10
+ export { default as BadgeField } from './BadgeField';
11
+ export { default as ReferenceField } from './ReferenceField';
12
+ export { default as ReferenceManyField } from './ReferenceManyField';
13
+ export { default as ArrayField } from './ArrayField';
14
+ export * from './TextField';
15
+ export * from './IdField';
16
+ export * from './NumberField';
17
+ export * from './DateField';
18
+ export * from './BooleanField';
19
+ export * from './BadgeField';
20
+ export * from './ReferenceField';
21
+ export * from './ReferenceManyField';
22
+ export * from './ArrayField';
23
+ export * from './CurrencyField';
@@ -0,0 +1,56 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type BaseFieldProps, type RaRecord } from '@strato-admin/core';
3
+ import { type RecordLinkType } from '../RecordLink';
4
+ /**
5
+ * Common props for all field components in strato-cloudscape.
6
+ */
7
+ export interface FieldProps<RecordType extends RaRecord = RaRecord> extends Omit<BaseFieldProps<RecordType>, 'source'> {
8
+ /**
9
+ * The property name in the record that should be displayed.
10
+ */
11
+ source?: string;
12
+ /**
13
+ * The label to display for this field. Usually inferred from the source.
14
+ */
15
+ label?: ReactNode;
16
+ /**
17
+ * Whether the field is sortable in a table.
18
+ * @default true
19
+ */
20
+ sortable?: boolean;
21
+ /**
22
+ * Whether to link the field to another page.
23
+ * - true: links to the 'edit' page of the current resource
24
+ * - 'edit' | 'show': links to the specified page type
25
+ * - string: a custom URL
26
+ * - function: (record, resource) => string
27
+ */
28
+ link?: RecordLinkType;
29
+ /**
30
+ * The text to display if the value is empty or null.
31
+ */
32
+ emptyText?: ReactNode;
33
+ /**
34
+ * Configuration for the inferred form input.
35
+ * - object: Props passed to the inferred Input component.
36
+ * - ReactElement: A specific Input component to use (escape hatch).
37
+ * - false: Excludes this field from forms.
38
+ */
39
+ input?: Record<string, any> | React.ReactElement | false;
40
+ /**
41
+ * Whether the field is required.
42
+ * This is used to automatically add validation to the inferred input
43
+ * and potentially show warnings in display views.
44
+ */
45
+ isRequired?: boolean;
46
+ /**
47
+ * Additional text to help the user fill in the field.
48
+ * Passed to the inferred Input component's FormField.
49
+ */
50
+ description?: ReactNode;
51
+ /**
52
+ * Text describing constraints (e.g., "Must be between 1 and 100").
53
+ * Passed to the inferred Input component's FormField.
54
+ */
55
+ constraintText?: ReactNode;
56
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { type FormProps as RaFormProps } from '@strato-admin/core';
3
+ export interface FormProps extends Omit<RaFormProps, 'children'> {
4
+ children?: React.ReactNode;
5
+ include?: string[];
6
+ exclude?: string[];
7
+ toolbar?: React.ReactNode;
8
+ }
9
+ export declare const Form: {
10
+ ({ children, include, exclude, toolbar, ...props }: FormProps): import("react/jsx-runtime").JSX.Element;
11
+ Field: (props: import("..").FormFieldProps) => import("react/jsx-runtime").JSX.Element;
12
+ };
13
+ export default Form;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Form as RaForm, useSaveContext, useInputSchema } from '@strato-admin/core';
4
+ import CloudscapeForm from '@cloudscape-design/components/form';
5
+ import SpaceBetween from '@cloudscape-design/components/space-between';
6
+ import { SaveButton } from '../button/SaveButton';
7
+ import { FormField } from '../input/FormField';
8
+ export const Form = ({ children, include, exclude, toolbar, ...props }) => {
9
+ const saveContext = useSaveContext();
10
+ const schemaChildren = useInputSchema();
11
+ const finalChildren = React.useMemo(() => {
12
+ const baseChildren = children || schemaChildren;
13
+ let result = React.Children.toArray(baseChildren);
14
+ if (include) {
15
+ result = result.filter((child) => React.isValidElement(child) && include.includes(child.props.source));
16
+ }
17
+ else if (exclude) {
18
+ result = result.filter((child) => React.isValidElement(child) && !exclude.includes(child.props.source));
19
+ }
20
+ return result;
21
+ }, [children, schemaChildren, include, exclude]);
22
+ const handleSubmit = async (values, event) => {
23
+ if (props.onSubmit) {
24
+ return props.onSubmit(values, event);
25
+ }
26
+ if (saveContext?.save) {
27
+ return saveContext.save(values, event);
28
+ }
29
+ };
30
+ return (_jsx(RaForm, { ...props, onSubmit: handleSubmit, children: _jsx(CloudscapeForm, { actions: toolbar || (_jsx(SpaceBetween, { direction: "horizontal", size: "xs", children: _jsx(SaveButton, {}) })), children: _jsx(SpaceBetween, { direction: "vertical", size: "l", children: finalChildren }) }) }));
31
+ };
32
+ Form.Field = FormField;
33
+ export default Form;
@@ -0,0 +1,2 @@
1
+ export * from './Form';
2
+ export { ValidationError } from '@strato-admin/core';
@@ -0,0 +1,2 @@
1
+ export * from './Form';
2
+ export { ValidationError } from '@strato-admin/core';
@@ -0,0 +1,22 @@
1
+ export * from '@strato-admin/core';
2
+ export * from './collection-hooks';
3
+ export * from './list';
4
+ export * from './detail';
5
+ export * from './edit';
6
+ export * from './create';
7
+ export * from './field';
8
+ export * from './input';
9
+ export * from './form';
10
+ export * from './layout';
11
+ export * from './theme';
12
+ export * from './button';
13
+ export * from './Admin';
14
+ export { default as RecordLink } from './RecordLink';
15
+ export * from './RecordLink';
16
+ export { Admin, type AdminProps } from './Admin';
17
+ export { Form, type FormProps } from './form';
18
+ export { List, type ListProps } from './list';
19
+ export { Create, type CreateProps } from './create';
20
+ export { Edit, type EditProps } from './edit';
21
+ export { Show, type ShowProps } from './detail';
22
+ export { type InputProps } from './input';
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ export * from '@strato-admin/core';
2
+ export * from './collection-hooks';
3
+ export * from './list';
4
+ export * from './detail';
5
+ export * from './edit';
6
+ export * from './create';
7
+ export * from './field';
8
+ export * from './input';
9
+ export * from './form';
10
+ export * from './layout';
11
+ export * from './theme';
12
+ export * from './button';
13
+ export * from './Admin';
14
+ export { default as RecordLink } from './RecordLink';
15
+ export * from './RecordLink';
16
+ // Explicitly export themed components to resolve ambiguity with strato-core (ra-core) re-exports
17
+ export { Admin } from './Admin';
18
+ export { Form } from './form';
19
+ export { List } from './list';
20
+ export { Create } from './create';
21
+ export { Edit } from './edit';
22
+ export { Show } from './detail';
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { InputProps } from './types';
3
+ export interface AttributeEditorItemProps {
4
+ source: string;
5
+ label?: string | false;
6
+ field?: React.ComponentType<any>;
7
+ validate?: any;
8
+ defaultValue?: any;
9
+ children?: React.ReactNode;
10
+ }
11
+ export declare const Item: (_props: AttributeEditorItemProps) => null;
12
+ export interface AttributeEditorProps extends Omit<InputProps, 'source'> {
13
+ source?: string;
14
+ children: React.ReactNode;
15
+ addButtonText?: string;
16
+ removeButtonText?: string;
17
+ empty?: React.ReactNode;
18
+ disableAddButton?: boolean;
19
+ hideAddButton?: boolean;
20
+ }
21
+ export declare const AttributeEditor: {
22
+ (props: AttributeEditorProps): import("react/jsx-runtime").JSX.Element;
23
+ Item: (_props: AttributeEditorItemProps) => null;
24
+ };
25
+ export default AttributeEditor;
@@ -0,0 +1,80 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React, { useMemo } from 'react';
3
+ import { useInput, RecordContextProvider, useResourceContext } from '@strato-admin/core';
4
+ import { useFieldArray, useFormContext } from 'react-hook-form';
5
+ import CloudscapeAttributeEditor from '@cloudscape-design/components/attribute-editor';
6
+ import Box from '@cloudscape-design/components/box';
7
+ import { FieldTitle } from './FieldTitle';
8
+ import TextInput from './TextInput';
9
+ import FormField from './FormField';
10
+ import { FormFieldContext, useFormFieldContext } from './FormFieldContext';
11
+ export const Item = (_props) => {
12
+ // This is a placeholder component used to collect props.
13
+ // The actual rendering is handled by the AttributeEditor.
14
+ return null;
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;
18
+ const { control } = useFormContext();
19
+ const contextValue = useFormFieldContext();
20
+ const resource = useResourceContext();
21
+ // Attempt to get source from context if not provided
22
+ const source = sourceProp || contextValue?.source || '';
23
+ const inputState = contextValue ??
24
+ useInput({
25
+ source,
26
+ validate,
27
+ defaultValue,
28
+ ...rest,
29
+ });
30
+ const { fields, append, remove } = useFieldArray({
31
+ control,
32
+ name: source,
33
+ });
34
+ const handleAdd = () => {
35
+ append({});
36
+ };
37
+ const handleRemove = (index) => {
38
+ remove(index);
39
+ };
40
+ const definition = useMemo(() => {
41
+ return React.Children.map(children, (child) => {
42
+ if (!React.isValidElement(child))
43
+ return null;
44
+ const childProps = child.props;
45
+ const childSource = childProps.source;
46
+ const childLabel = childProps.label;
47
+ const childValidate = childProps.validate;
48
+ // Determine if the field is required by checking validators
49
+ const isRequired = Array.isArray(childValidate)
50
+ ? childValidate.some((v) => v.isRequired)
51
+ : childValidate?.isRequired || childProps.isRequired;
52
+ return {
53
+ label: _jsx(FieldTitle, { label: childLabel, source: childSource, resource: resource, isRequired: isRequired }),
54
+ control: (item, index) => {
55
+ const prefixedSource = `${source}.${index}.${childSource}`;
56
+ let content;
57
+ if (child.type === Item) {
58
+ const { field: FieldComponent, children: itemChildren, validate: itemValidate, defaultValue: itemDefaultValue, } = childProps;
59
+ content = itemChildren ? (_jsx(FormField, { source: prefixedSource, label: false, validate: itemValidate, defaultValue: itemDefaultValue, children: itemChildren })) : FieldComponent ? (_jsx(FieldComponent, { source: prefixedSource, label: false, validate: itemValidate, defaultValue: itemDefaultValue })) : (_jsx(TextInput, { source: prefixedSource, label: false, validate: itemValidate, defaultValue: itemDefaultValue }));
60
+ }
61
+ else {
62
+ // Standard child (e.g. TextInput)
63
+ content = React.cloneElement(child, {
64
+ source: prefixedSource,
65
+ label: false,
66
+ });
67
+ }
68
+ return (_jsx(RecordContextProvider, { value: item, children: _jsx(Box, { padding: { top: 's' }, children: content }) }));
69
+ },
70
+ };
71
+ })?.filter(Boolean);
72
+ }, [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 }) }));
74
+ if (contextValue) {
75
+ return inner;
76
+ }
77
+ return (_jsx(FormFieldContext.Provider, { value: { ...inputState, source }, children: _jsx(FormField, { ...props, source: source, children: inner }) }));
78
+ };
79
+ AttributeEditor.Item = Item;
80
+ export default AttributeEditor;