@commercelayer/app-elements 7.13.0 → 7.14.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 (69) hide show
  1. package/dist/{CodeEditorComponent-aj99riRd.js → CodeEditorComponent-txM4ls17.js} +2 -2
  2. package/dist/{InputDateComponent-IsJB6qOP.js → InputDateComponent-C4QUlrmn.js} +2 -2
  3. package/dist/{RuleEngineComponent-DZhv94I7.js → RuleEngineComponent-dEe0FTBs.js} +266 -261
  4. package/dist/{en-Ccxurm3G.js → en-B-7ylwWx.js} +29 -1
  5. package/dist/{fetchCoreResourcesSuggestions-DuyGOmZK.js → fetchCoreResourcesSuggestions-DZuapPGj.js} +1 -1
  6. package/dist/helpers/numbers.d.ts +25 -0
  7. package/dist/helpers/numbers.test.d.ts +1 -0
  8. package/dist/hooks/useConfirmDialog.test.d.ts +1 -0
  9. package/dist/hooks/useOverlay.d.ts +9 -1
  10. package/dist/{it-C8-LXpKU.js → it-BXPKgQsm.js} +29 -1
  11. package/dist/locales/en.d.ts +28 -0
  12. package/dist/{main-DoRznkuw.js → main-Op1RV9MX.js} +14115 -12393
  13. package/dist/main.d.ts +8 -3
  14. package/dist/main.js +176 -166
  15. package/dist/mocks/data/core_schemas.d.ts +2 -0
  16. package/dist/mocks/data/event_stores.d.ts +2 -0
  17. package/dist/mocks/data/event_stores.test.d.ts +1 -0
  18. package/dist/{parseISO-Byyj1mNB.js → parseISO-C1OS0R6q.js} +1 -1
  19. package/dist/providers/TokenProvider/MockTokenProvider.d.ts +1 -1
  20. package/dist/providers/TokenProvider/TokenProvider.d.ts +1 -1
  21. package/dist/style.css +1 -1
  22. package/dist/tailwind.global.css +8 -4
  23. package/dist/ui/atoms/AvatarLetter/AvatarLetter.d.ts +6 -1
  24. package/dist/ui/atoms/PageHeading/PageHeading.d.ts +22 -4
  25. package/dist/ui/atoms/RadialProgress.d.ts +2 -2
  26. package/dist/ui/atoms/Section.d.ts +35 -0
  27. package/dist/ui/atoms/Spacer.d.ts +29 -4
  28. package/dist/ui/atoms/Stack.d.ts +48 -2
  29. package/dist/ui/atoms/Table/Table.d.ts +8 -0
  30. package/dist/ui/atoms/Tabs.d.ts +8 -0
  31. package/dist/ui/atoms/VisibilityTrigger.d.ts +19 -0
  32. package/dist/ui/atoms/VisibilityTrigger.test.d.ts +1 -0
  33. package/dist/ui/composite/Address.d.ts +9 -0
  34. package/dist/ui/composite/ListDetailsItem.d.ts +14 -1
  35. package/dist/ui/composite/PageLayout.d.ts +43 -24
  36. package/dist/ui/composite/PageLoading.d.ts +35 -0
  37. package/dist/ui/composite/PageLoading.test.d.ts +1 -0
  38. package/dist/ui/composite/PageSkeleton.d.ts +6 -0
  39. package/dist/ui/composite/Routes/LoadingPage.test.d.ts +1 -0
  40. package/dist/ui/forms/InputSelect/InputSelect.d.ts +8 -0
  41. package/dist/ui/internals/Overlay.test.d.ts +1 -0
  42. package/dist/ui/internals/bodyScrollLock.d.ts +2 -0
  43. package/dist/ui/internals/overlayContext.d.ts +36 -0
  44. package/dist/ui/resources/ResourceAddress/ResourceAddress.d.ts +12 -2
  45. package/dist/ui/resources/ResourceDetails/ResourceDetails.d.ts +9 -0
  46. package/dist/ui/resources/ResourceDetails/ResourceDetails.test.d.ts +1 -0
  47. package/dist/ui/resources/ResourceDetailsModal/ResourceAttributes.d.ts +11 -0
  48. package/dist/ui/resources/ResourceDetailsModal/ResourceDetailsContent.d.ts +43 -0
  49. package/dist/ui/resources/ResourceDetailsModal/ResourceDetailsContent.test.d.ts +1 -0
  50. package/dist/ui/resources/ResourceDetailsModal/ResourceEvents.d.ts +15 -0
  51. package/dist/ui/resources/ResourceDetailsModal/index.d.ts +2 -0
  52. package/dist/ui/resources/ResourceDetailsModal/resourceFields.d.ts +19 -0
  53. package/dist/ui/resources/ResourceDetailsModal/resourceFields.test.d.ts +1 -0
  54. package/dist/ui/resources/ResourceDetailsModal/useInfiniteScrollCursor.d.ts +39 -0
  55. package/dist/ui/resources/ResourceDetailsModal/useResourceDetailsModal.d.ts +23 -0
  56. package/dist/ui/resources/ResourceMetadata/ResourceMetadata.d.ts +9 -0
  57. package/dist/ui/resources/ResourceTags.d.ts +21 -1
  58. package/dist/ui/resources/ResourceTags.test.d.ts +1 -0
  59. package/dist/ui/resources/useResourceFilters/types.d.ts +26 -2
  60. package/dist/ui/resources/useResourceFilters/utils.d.ts +10 -0
  61. package/dist/ui/resources/useResourceList/index.d.ts +1 -0
  62. package/dist/ui/resources/useResourceList/resourceListSignals.d.ts +46 -0
  63. package/dist/ui/resources/useResourceList/resourceListSignals.integration.test.d.ts +1 -0
  64. package/dist/ui/resources/useResourceList/resourceListSignals.test.d.ts +1 -0
  65. package/dist/ui/resources/useResourceTable/types.d.ts +93 -23
  66. package/dist/ui/resources/useResourceTable/useResourceTable.test.d.ts +1 -0
  67. package/package.json +4 -3
  68. package/dist/ui/resources/useResourceList/VisibilityTrigger.d.ts +0 -8
  69. /package/dist/{ui/resources/useResourceList/VisibilityTrigger.test.d.ts → dictionaries/orders.test.d.ts} +0 -0
@@ -147,15 +147,30 @@ export type FilterItemOptions = BaseFilterItem & {
147
147
  */
148
148
  component: "inputSelect";
149
149
  /**
150
- * props required for the UI component
150
+ * props required for the UI component.
151
+ *
152
+ * Either a fixed list of `options` — statuses, kinds, anything the app
153
+ * already knows — or a `resource` the options are fetched from.
151
154
  */
152
- props: Pick<InputResourceGroupProps, "resource" | "fieldForLabel" | "fieldForValue" | "searchBy" | "sortBy" | "filters" | "hideWhenSingleItem"> & {
155
+ props: ({
156
+ /**
157
+ * The options to choose from. An option can be hidden from the UI
158
+ * and still be accepted in the query, e.g. a status that is only
159
+ * ever set through a predefined link.
160
+ */
161
+ options: Array<{
162
+ label: string;
163
+ value: string;
164
+ isHidden?: boolean;
165
+ }>;
166
+ } | (Pick<InputResourceGroupProps, "resource" | "fieldForLabel" | "fieldForValue" | "searchBy" | "sortBy" | "filters" | "hideWhenSingleItem"> & {
153
167
  /**
154
168
  * How many options to load upfront. Capped at 25 by the Core API, which
155
169
  * is why `searchBy` should be set when more options exist.
156
170
  * @default 25
157
171
  */
158
172
  limit?: number;
173
+ })) & {
159
174
  placeholder?: string;
160
175
  isClearable?: boolean;
161
176
  /**
@@ -212,6 +227,15 @@ export type FiltersInstructionItem = FilterItemOptions | FilterItemTextSearch |
212
227
  export type FiltersInstructions = FiltersInstructionItem[];
213
228
  export declare function isItemOptions(item: FiltersInstructionItem): item is FilterItemOptions;
214
229
  export declare function isTextSearch(item: FiltersInstructionItem): item is FilterItemTextSearch;
230
+ /**
231
+ * The predicate of the free text filter shown in the search bar, if any.
232
+ *
233
+ * Not simply the first `textSearch` instruction: apps also declare `textSearch`
234
+ * items for predicates they only want whitelisted (hidden ones driving tabs, for
235
+ * instance), and those can come first. There is at most one `searchBar` in a set
236
+ * of instructions, so this is unambiguous.
237
+ */
238
+ export declare function getSearchBarPredicate(instructions: FiltersInstructions): string | undefined;
215
239
  export declare function isCurrencyRange(item: FiltersInstructionItem): item is FilterItemCurrencyRange;
216
240
  export declare function isGroupedPredicates(item: FiltersInstructionItem): item is FilterItemGroupedPredicates;
217
241
  /**
@@ -27,3 +27,13 @@ export declare function getActiveFilterCountFromUrl({ includeTextSearch, instruc
27
27
  queryString: string;
28
28
  }): number;
29
29
  export declare function getAllowedValuesFromItemOptions(instructionItem: FilterItemOptions): string[] | undefined;
30
+ /**
31
+ * Whether an `options` filter holds a single value rather than a list.
32
+ *
33
+ * Two components can be single-valued and they say so differently: a toggle
34
+ * button through `mode`, a select through `isMulti`. Anything reading a filter
35
+ * value has to know which, so the value can be unwrapped from the array the URL
36
+ * always parses into — a predicate like `archived_at_null` expects `"hide"`,
37
+ * not `["hide"]`.
38
+ */
39
+ export declare function isSingleValueOptionsItem(instructionItem: FilterItemOptions): boolean;
@@ -1 +1,2 @@
1
+ export { refreshResourceLists, removeFromResourceLists, } from './resourceListSignals';
1
2
  export { type ResourceListItemTemplateProps, type ResourceListProps, type UseResourceListConfig, useResourceList, } from './useResourceList';
@@ -0,0 +1,46 @@
1
+ import { ListableResourceType } from '@commercelayer/sdk';
2
+ /**
3
+ * What a mounted list is being asked to do.
4
+ * - `removeItem` drops a single row without any request
5
+ * - `refresh` refetches from the first page
6
+ */
7
+ type ResourceListSignal = {
8
+ kind: "removeItem";
9
+ resourceId: string;
10
+ } | {
11
+ kind: "refresh";
12
+ };
13
+ type ResourceListSubscriber = (signal: ResourceListSignal) => void;
14
+ /**
15
+ * Subscribe a mounted list to the signals for a resource type.
16
+ * Called by `useResourceList`; returns the unsubscribe function.
17
+ */
18
+ export declare function subscribeToResourceLists(type: ListableResourceType, subscriber: ResourceListSubscriber): () => void;
19
+ /**
20
+ * Drop a row from every mounted list of the given resource type, with no
21
+ * request. Call it right after a successful delete.
22
+ *
23
+ * Needed when the component that deletes is not the one rendering the list —
24
+ * typically a details drawer rendered as a sibling of the list, which leaves the
25
+ * list mounted, so it would otherwise keep showing the deleted row until the
26
+ * page is reloaded. Lists that do not hold the row ignore the signal, and the
27
+ * total record count is adjusted for those that do.
28
+ *
29
+ * @example
30
+ * await sdkClient.stock_items.delete(stockItem.id)
31
+ * removeFromResourceLists("stock_items", stockItem.id)
32
+ */
33
+ export declare function removeFromResourceLists(type: ListableResourceType, resourceId: string): void;
34
+ /**
35
+ * Refetch every mounted list of the given resource type from the first page.
36
+ *
37
+ * Prefer `removeFromResourceLists` after a delete: it is instant, and it neither
38
+ * flashes the loading skeleton nor renumbers an infinite list mid-scroll. Reach
39
+ * for this one when rows were created or edited elsewhere and the list content
40
+ * can no longer be patched locally.
41
+ *
42
+ * A signal emitted while no list is mounted is a no-op — which is harmless,
43
+ * since a list fetches on mount anyway.
44
+ */
45
+ export declare function refreshResourceLists(type: ListableResourceType): void;
46
+ export {};
@@ -1,4 +1,4 @@
1
- import { ListableResourceType } from '@commercelayer/sdk';
1
+ import { ListableResourceType, ResourceSortFields } from '@commercelayer/sdk';
2
2
  import { FC, ReactNode } from 'react';
3
3
  import { SectionProps } from '../../atoms/Section';
4
4
  import { Resource } from '../useResourceList/listFetcher';
@@ -34,35 +34,97 @@ export interface ResourceTableColumn<TResource extends ListableResourceType> {
34
34
  */
35
35
  align?: "left" | "right" | "center";
36
36
  /**
37
- * Optional CSS class applied to the column header, typically for width
38
- * control (e.g. `"w-1/2"`).
37
+ * What the column holds. Sets its width — as a share of the table, so it stays
38
+ * liquid plus alignment and truncation, from one scale shared by every app
39
+ * (see `columnKindClassName`). Leave it off for the column that should absorb
40
+ * the leftover space: the name, email or SKU the row is about.
41
+ *
42
+ * Prefer this over `width`: it is what keeps a status column the same size in
43
+ * every app, and it makes the loading and loaded tables identical, since the
44
+ * widths no longer depend on the cell content.
45
+ */
46
+ kind?: ResourceTableColumnKind;
47
+ /**
48
+ * Escape hatch for a width `kind` cannot express, as a CSS class applied to
49
+ * the column header (e.g. `"w-1/2"`). Overrides the `kind` width.
50
+ *
51
+ * Note the table lays out with `table-layout: fixed`, so a class means what it
52
+ * says: a column narrower than its content clips rather than growing.
39
53
  */
40
54
  width?: string;
41
55
  /**
42
- * Hide this column below the given breakpoint; it is shown at that width and
43
- * up. These are app-elements' own breakpoints (see `styles/global.css`, which
44
- * resets Tailwind's defaults): `md` 768px, `lg` 992px, `xl` 1280px. There is
56
+ * When this column starts being shown, overriding the default.
57
+ *
58
+ * By default a table shows only its first column on mobile — a phone has room
59
+ * for what the row is about and little else — and everything else from `md` up.
60
+ * Set this to widen or narrow that:
61
+ *
62
+ * - `"lg"` / `"xl"` — appear later than the default (a low-value column)
63
+ * - `"never"` — always visible, mobile included. For the one column that is the
64
+ * point of the table: a stock item's quantity, a price, a gift card balance.
65
+ *
66
+ * These are app-elements' own breakpoints (see `styles/global.css`, which resets
67
+ * Tailwind's defaults): `md` 768px, `lg` 992px, `xl` 1280px. There is
45
68
  * deliberately no `sm`.
46
69
  *
47
- * Common cases: `"md"` hides on mobile (shown on tablet + desktop), `"lg"`
48
- * shows on desktop only. The column's data is still fetched; only its
49
- * rendering is suppressed via CSS, so there is no layout shift on resize.
70
+ * The column's data is still fetched either way; only its rendering is
71
+ * suppressed, via CSS, so nothing shifts on resize.
50
72
  */
51
- hideBelow?: "md" | "lg" | "xl";
73
+ hideBelow?: "md" | "lg" | "xl" | "never";
52
74
  /**
53
- * When set, the column becomes sortable and this value is the CommerceLayer
54
- * SDK sort attribute it sorts by (e.g. `"created_at"`).
75
+ * When set, the column becomes sortable and this value is the attribute it
76
+ * sorts by (e.g. `"created_at"`).
77
+ *
78
+ * Only attributes the API can actually sort by are accepted: the type is the
79
+ * resource's own sortable set, taken from the SDK (see `SortableAttribute`).
80
+ * Attributes reached through a relationship (`sku.code`, a market's name) are
81
+ * not sortable, so those columns stay static.
82
+ *
83
+ * On a `metricsQuery` table the value is a Metrics attribute instead
84
+ * (`"order.placed_at"`) — see `MetricsAttribute`.
55
85
  *
56
- * Sorting is server-side: clicking the header drives the SDK `sort` query
57
- * param and refetches. Rows are never reordered client-side.
86
+ * Sorting is server-side: the attribute goes into the SDK `sort` query param and
87
+ * the list refetches. Rows are never reordered client-side.
88
+ *
89
+ * Declaring it does not make the header interactive — table headers are inert.
90
+ * It marks the column as sortable and names the attribute, which is what a sort
91
+ * control outside the table reads to build its options.
58
92
  */
59
- sortBy?: string;
93
+ sortBy?: SortableAttribute<TResource> | MetricsAttribute;
60
94
  }
95
+ /**
96
+ * The kinds of column a resource table has, each with a width, an alignment and
97
+ * a truncation rule. Deliberately a short list: the point is that a status column
98
+ * is the same width in every app, which only holds if apps pick from a scale
99
+ * rather than sizing columns one by one.
100
+ *
101
+ * `text` is for the secondary strings a row carries — a market, a stock location,
102
+ * a customer, an origin. Without it they would split the leftover space evenly
103
+ * with the column the row is actually about, which is rarely what you want.
104
+ */
105
+ export type ResourceTableColumnKind = "text" | "code" | "status" | "datetime" | "amount" | "count" | "actions";
106
+ /**
107
+ * The attributes the API can sort a given resource by, straight from the SDK's
108
+ * `ResourceSortFields`. Every resource adds the shared `id`, `reference`,
109
+ * `reference_origin`, `created_at` and `updated_at` to its own set.
110
+ *
111
+ * This is the single source of truth for whether a column can be sortable: the
112
+ * API rejects anything else, and computed values (a status derived from several
113
+ * timestamps, a relationship's name) are not in it by definition.
114
+ */
115
+ export type SortableAttribute<TResource extends ListableResourceType> = Extract<keyof ResourceSortFields[TResource], string>;
116
+ /**
117
+ * A Metrics API sort attribute, always namespaced by its entity
118
+ * (`"order.placed_at"`). Metrics has its own attribute names, outside the SDK's
119
+ * resource types, so these can only be checked by shape — the dot is what tells
120
+ * them apart from a Core attribute.
121
+ */
122
+ export type MetricsAttribute = `${string}.${string}`;
61
123
  /**
62
124
  * SDK sort expression, e.g. `"created_at"` (asc) or `"-created_at"` (desc).
63
125
  * `undefined` means no explicit table sort is applied.
64
126
  */
65
- export type ResourceTableSort = string | undefined;
127
+ export type ResourceTableSort<TResource extends ListableResourceType = ListableResourceType> = SortableAttribute<TResource> | `-${SortableAttribute<TResource>}` | MetricsAttribute | `-${MetricsAttribute}` | undefined;
66
128
  export type UseResourceTableConfig<TResource extends ListableResourceType> = Omit<UseResourceListConfig<TResource>, "metricsQuery" | "query"> & {
67
129
  /** The columns to render, in display order. */
68
130
  columns: Array<ResourceTableColumn<TResource>>;
@@ -121,18 +183,18 @@ export type UseResourceTableConfig<TResource extends ListableResourceType> = Omi
121
183
  * Pass together with `onSortChange` to own the sort state (e.g. persist it
122
184
  * in the URL). When omitted the table manages sort internally.
123
185
  */
124
- sort?: ResourceTableSort;
186
+ sort?: ResourceTableSort<TResource>;
125
187
  /**
126
- * Called when the user changes the sort. Provide together with `sort` for
127
- * controlled mode; the callback receives the new SDK sort expression (or
128
- * `undefined` when sorting is cleared).
188
+ * Called when the sort changes. Provide together with `sort` for controlled
189
+ * mode; the callback receives the new SDK sort expression (or `undefined` when
190
+ * sorting is cleared).
129
191
  */
130
- onSortChange?: (sort: ResourceTableSort) => void;
192
+ onSortChange?: (sort: ResourceTableSort<TResource>) => void;
131
193
  /**
132
194
  * Initial sort used only when the table manages sort internally
133
195
  * (uncontrolled). Ignored when `sort`/`onSortChange` are provided.
134
196
  */
135
- defaultSort?: ResourceTableSort;
197
+ defaultSort?: ResourceTableSort<TResource>;
136
198
  };
137
199
  /** Props of the `ResourceTable` component returned by the hook. */
138
200
  export interface ResourceTableProps {
@@ -178,5 +240,13 @@ export interface UseResourceTableReturn<TResource extends ListableResourceType>
178
240
  refresh: () => void;
179
241
  hasMorePages?: boolean;
180
242
  /** The active sort (SDK sort expression), whether controlled or internal. */
181
- sort: ResourceTableSort;
243
+ sort: ResourceTableSort<TResource>;
244
+ /**
245
+ * Sets the sort, for a control outside the table to drive — a field + direction
246
+ * picker, say. Table headers are inert (see `sortBy`).
247
+ *
248
+ * In controlled mode (`sort` + `onSortChange`) this calls `onSortChange` rather
249
+ * than holding state of its own.
250
+ */
251
+ setSort: (sort: ResourceTableSort<TResource>) => void;
182
252
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commercelayer/app-elements",
3
- "version": "7.13.0",
3
+ "version": "7.14.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -61,6 +61,7 @@
61
61
  "react-select": "^5.10.2",
62
62
  "react-toastify": "^11.1.0",
63
63
  "react-tooltip": "^5.30.1",
64
+ "stable-hash": "^0.0.6",
64
65
  "swr": "^2.4.2",
65
66
  "ts-invariant": "^0.10.3",
66
67
  "type-fest": "^5.7.0",
@@ -101,8 +102,8 @@
101
102
  "wouter": "^3.x"
102
103
  },
103
104
  "scripts": {
104
- "build": "tsc && vite build && pnpm build:css-vendor && pnpm build:tailwind-cfg",
105
- "build:tailwind-cfg": "cp ./src/styles/global.css ./dist/tailwind.global.css",
105
+ "build": "tsc && vite build && pnpm build:css-vendor",
106
+ "build:watch": "pnpm dlx concurrently@10 --kill-others --names vendor,lib --prefix-colors cyan,magenta \"pnpm build:css-vendor --watch\" \"APP_ELEMENTS_WATCH=true vite build --watch\"",
106
107
  "build:css-vendor": "pnpm dlx @tailwindcss/cli -i ./src/styles/vendor.css -o ./dist/vendor.css --minify",
107
108
  "check": "pnpm biome check",
108
109
  "check:fix": "pnpm biome check --write",
@@ -1,8 +0,0 @@
1
- import { default as React, JSX } from 'react';
2
- interface VisibilityTriggerProps extends React.HTMLAttributes<HTMLDivElement> {
3
- rootMargin?: string;
4
- callback: (entry: IntersectionObserverEntry) => void;
5
- enabled: boolean;
6
- }
7
- export declare function VisibilityTrigger({ rootMargin, enabled, callback, ...rest }: VisibilityTriggerProps): JSX.Element;
8
- export {};