@commercelayer/app-elements 7.13.0 → 7.15.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.
- package/dist/{CodeEditorComponent-aj99riRd.js → CodeEditorComponent-_TYzE5JR.js} +2 -2
- package/dist/{InputDateComponent-IsJB6qOP.js → InputDateComponent-hOMN2atv.js} +2 -2
- package/dist/{RuleEngineComponent-DZhv94I7.js → RuleEngineComponent-CabW-AtC.js} +266 -261
- package/dist/{en-Ccxurm3G.js → en-B-7ylwWx.js} +29 -1
- package/dist/{fetchCoreResourcesSuggestions-DuyGOmZK.js → fetchCoreResourcesSuggestions-CkzjWPYB.js} +1 -1
- package/dist/helpers/numbers.d.ts +25 -0
- package/dist/helpers/numbers.test.d.ts +1 -0
- package/dist/hooks/useConfirmDialog.test.d.ts +1 -0
- package/dist/hooks/useOverlay.d.ts +9 -1
- package/dist/{it-C8-LXpKU.js → it-BXPKgQsm.js} +29 -1
- package/dist/locales/en.d.ts +28 -0
- package/dist/{main-DoRznkuw.js → main-DClsDolL.js} +14219 -12445
- package/dist/main.d.ts +8 -3
- package/dist/main.js +176 -166
- package/dist/mocks/data/core_schemas.d.ts +2 -0
- package/dist/mocks/data/event_stores.d.ts +2 -0
- package/dist/mocks/data/event_stores.test.d.ts +1 -0
- package/dist/{parseISO-Byyj1mNB.js → parseISO-4tQNE1Vc.js} +1 -1
- package/dist/providers/TokenProvider/MockTokenProvider.d.ts +1 -1
- package/dist/providers/TokenProvider/TokenProvider.d.ts +1 -1
- package/dist/style.css +1 -1
- package/dist/tailwind.global.css +8 -4
- package/dist/ui/atoms/AvatarLetter/AvatarLetter.d.ts +6 -1
- package/dist/ui/atoms/AvatarLetter/colors.d.ts +18 -2
- package/dist/ui/atoms/PageHeading/PageHeading.d.ts +22 -4
- package/dist/ui/atoms/RadialProgress.d.ts +2 -2
- package/dist/ui/atoms/Section.d.ts +35 -0
- package/dist/ui/atoms/Spacer.d.ts +29 -4
- package/dist/ui/atoms/Stack.d.ts +48 -2
- package/dist/ui/atoms/Table/Table.d.ts +8 -0
- package/dist/ui/atoms/Tabs.d.ts +8 -0
- package/dist/ui/atoms/VisibilityTrigger.d.ts +19 -0
- package/dist/ui/atoms/VisibilityTrigger.test.d.ts +1 -0
- package/dist/ui/composite/Address.d.ts +9 -0
- package/dist/ui/composite/ListDetailsItem.d.ts +14 -1
- package/dist/ui/composite/PageLayout.d.ts +43 -24
- package/dist/ui/composite/PageLoading.d.ts +35 -0
- package/dist/ui/composite/PageLoading.test.d.ts +1 -0
- package/dist/ui/composite/PageSkeleton.d.ts +6 -0
- package/dist/ui/composite/Routes/LoadingPage.test.d.ts +1 -0
- package/dist/ui/forms/InputSelect/InputSelect.d.ts +17 -0
- package/dist/ui/forms/InputSelect/styles.d.ts +6 -1
- package/dist/ui/internals/Overlay.test.d.ts +1 -0
- package/dist/ui/internals/bodyScrollLock.d.ts +2 -0
- package/dist/ui/internals/overlayContext.d.ts +36 -0
- package/dist/ui/resources/ResourceAddress/ResourceAddress.d.ts +12 -2
- package/dist/ui/resources/ResourceDetails/ResourceDetails.d.ts +9 -0
- package/dist/ui/resources/ResourceDetails/ResourceDetails.test.d.ts +1 -0
- package/dist/ui/resources/ResourceDetailsModal/ResourceAttributes.d.ts +11 -0
- package/dist/ui/resources/ResourceDetailsModal/ResourceDetailsContent.d.ts +43 -0
- package/dist/ui/resources/ResourceDetailsModal/ResourceDetailsContent.test.d.ts +1 -0
- package/dist/ui/resources/ResourceDetailsModal/ResourceEvents.d.ts +15 -0
- package/dist/ui/resources/ResourceDetailsModal/index.d.ts +2 -0
- package/dist/ui/resources/ResourceDetailsModal/resourceFields.d.ts +19 -0
- package/dist/ui/resources/ResourceDetailsModal/resourceFields.test.d.ts +1 -0
- package/dist/ui/resources/ResourceDetailsModal/useInfiniteScrollCursor.d.ts +39 -0
- package/dist/ui/resources/ResourceDetailsModal/useResourceDetailsModal.d.ts +23 -0
- package/dist/ui/resources/ResourceMetadata/ResourceMetadata.d.ts +9 -0
- package/dist/ui/resources/ResourceTags.d.ts +21 -1
- package/dist/ui/resources/ResourceTags.test.d.ts +1 -0
- package/dist/ui/resources/useResourceFilters/FiltersBarSelect.d.ts +22 -0
- package/dist/ui/resources/useResourceFilters/types.d.ts +45 -2
- package/dist/ui/resources/useResourceFilters/useResourceSelectOptions.d.ts +35 -0
- package/dist/ui/resources/useResourceFilters/utils.d.ts +18 -1
- package/dist/ui/resources/useResourceList/index.d.ts +1 -0
- package/dist/ui/resources/useResourceList/resourceListSignals.d.ts +46 -0
- package/dist/ui/resources/useResourceList/resourceListSignals.integration.test.d.ts +1 -0
- package/dist/ui/resources/useResourceList/resourceListSignals.test.d.ts +1 -0
- package/dist/ui/resources/useResourceTable/types.d.ts +93 -23
- package/dist/ui/resources/useResourceTable/useResourceTable.test.d.ts +1 -0
- package/package.json +4 -3
- package/dist/ui/resources/useResourceList/VisibilityTrigger.d.ts +0 -8
- /package/dist/{ui/resources/useResourceList/VisibilityTrigger.test.d.ts → dictionaries/orders.test.d.ts} +0 -0
|
@@ -3,6 +3,14 @@ import { EditMetadataOverlayProps } from '../../../hooks/useEditMetadataOverlay'
|
|
|
3
3
|
interface MetadataOverlay extends Omit<EditMetadataOverlayProps, "resourceId" | "resourceType"> {
|
|
4
4
|
}
|
|
5
5
|
export interface ResourceMetadataProps {
|
|
6
|
+
/**
|
|
7
|
+
* How the block renders, overriding what it infers from where it sits.
|
|
8
|
+
*
|
|
9
|
+
* Inferred by default — `PageLayout`'s sidebar slot reports `"sidebar"`, while a
|
|
10
|
+
* page and a drawer both report the wider `"default"`. Pass it only to force a
|
|
11
|
+
* rendering the surrounding surface would not choose.
|
|
12
|
+
*/
|
|
13
|
+
variant?: "default" | "sidebar";
|
|
6
14
|
resourceType: ListableResourceType;
|
|
7
15
|
resourceId: string;
|
|
8
16
|
/**
|
|
@@ -18,6 +26,7 @@ export declare const isUpdatableType: (value: any) => value is UpdatableType;
|
|
|
18
26
|
* More in detail the `metadata` attribute is a JSON object, customizable for several purposes, and this component will allow to show and manage its keys with a simple (string kind) values.
|
|
19
27
|
*/
|
|
20
28
|
export declare const ResourceMetadata: import('../../atoms/SkeletonTemplate').SkeletonTemplateComponent<{
|
|
29
|
+
variant?: "default" | "sidebar" | undefined;
|
|
21
30
|
resourceType: ListableResourceType;
|
|
22
31
|
resourceId: string;
|
|
23
32
|
overlay?: MetadataOverlay | undefined;
|
|
@@ -1,9 +1,28 @@
|
|
|
1
1
|
import { ListableResourceType } from '@commercelayer/sdk';
|
|
2
2
|
import { EditTagsOverlayProps } from '../../hooks/useEditTagsOverlay';
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The resources the API can tag, as a value so that a caller can ask at runtime —
|
|
5
|
+
* `ResourceAdminBlocks` leaves the block out for a stock item or an import.
|
|
6
|
+
*
|
|
7
|
+
* The SDK declares an `isTaggable()` helper and a `taggableResources` array in its
|
|
8
|
+
* types but ships neither in its build, so calling them typechecks and then throws.
|
|
9
|
+
* Hence our own list, checked against `ListableResourceType` by `satisfies`.
|
|
10
|
+
*/
|
|
11
|
+
export declare const taggableResources: readonly ["addresses", "bundles", "coupons", "customers", "gift_cards", "line_items", "line_item_options", "order_subscriptions", "orders", "buy_x_pay_y_promotions", "external_promotions", "fixed_amount_promotions", "fixed_price_promotions", "flex_promotions", "free_gift_promotions", "free_shipping_promotions", "percentage_discount_promotions", "returns", "shipments", "shipping_methods", "sku_options", "skus"];
|
|
12
|
+
export type TaggableResource = (typeof taggableResources)[number];
|
|
13
|
+
/** Whether the API can tag this resource. */
|
|
14
|
+
export declare function isTaggableResource(resourceType: ListableResourceType): resourceType is TaggableResource;
|
|
4
15
|
interface TagsOverlay extends Omit<EditTagsOverlayProps, "resourceId" | "resourceType"> {
|
|
5
16
|
}
|
|
6
17
|
export interface ResourceTagsProps {
|
|
18
|
+
/**
|
|
19
|
+
* How the block renders, overriding what it infers from where it sits.
|
|
20
|
+
*
|
|
21
|
+
* Inferred by default — `PageLayout`'s sidebar slot reports `"sidebar"`, while a
|
|
22
|
+
* page and a drawer both report the wider `"default"`. Pass it only to force a
|
|
23
|
+
* rendering the surrounding surface would not choose.
|
|
24
|
+
*/
|
|
25
|
+
variant?: "default" | "sidebar";
|
|
7
26
|
resourceType: TaggableResource;
|
|
8
27
|
resourceId: string;
|
|
9
28
|
/**
|
|
@@ -19,6 +38,7 @@ export interface ResourceTagsProps {
|
|
|
19
38
|
* This component generates an all-in-one visualization and editing interface for managing tags relationship of requested resource.
|
|
20
39
|
*/
|
|
21
40
|
export declare const ResourceTags: import('../atoms/SkeletonTemplate').SkeletonTemplateComponent<{
|
|
41
|
+
variant?: "default" | "sidebar" | undefined;
|
|
22
42
|
resourceType: TaggableResource;
|
|
23
43
|
resourceId: string;
|
|
24
44
|
overlay?: TagsOverlay
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { JSX } from 'react';
|
|
2
|
+
import { FilterItemOptions, FiltersInstructions } from './types';
|
|
3
|
+
export interface FiltersBarSelectProps {
|
|
4
|
+
/** The promoted filter, already known to be an `inputSelect` in the bar. */
|
|
5
|
+
item: FilterItemOptions;
|
|
6
|
+
instructions: FiltersInstructions;
|
|
7
|
+
queryString: string;
|
|
8
|
+
predicateWhitelist: string[];
|
|
9
|
+
onUpdate: (queryString: string) => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A filter rendered in `FiltersBar` rather than in the drawer.
|
|
13
|
+
*
|
|
14
|
+
* It works straight on the query string, as the search bar does: there is no form
|
|
15
|
+
* around it to submit, so a choice applies immediately. Single-valued — the
|
|
16
|
+
* trigger has one line to state what the page is showing — while the predicate
|
|
17
|
+
* stays `_in`, so links shared before the filter was promoted keep working.
|
|
18
|
+
*/
|
|
19
|
+
export declare function FiltersBarSelect({ item, instructions, queryString, predicateWhitelist, onUpdate, }: FiltersBarSelectProps): JSX.Element | null;
|
|
20
|
+
export declare namespace FiltersBarSelect {
|
|
21
|
+
var displayName: string;
|
|
22
|
+
}
|
|
@@ -147,15 +147,49 @@ export type FilterItemOptions = BaseFilterItem & {
|
|
|
147
147
|
*/
|
|
148
148
|
component: "inputSelect";
|
|
149
149
|
/**
|
|
150
|
-
*
|
|
150
|
+
* Where the field is rendered.
|
|
151
|
+
*
|
|
152
|
+
* `"bar"` promotes it out of the drawer and into `FiltersBar`, as a
|
|
153
|
+
* fixed-width trigger beside the search field — for the one filter a page
|
|
154
|
+
* is really read through, such as the price list on prices or the stock
|
|
155
|
+
* location on inventory. The drawer then skips it, the way it already
|
|
156
|
+
* skips the search bar: one control, one home.
|
|
157
|
+
*
|
|
158
|
+
* A promoted filter produces no pill (the trigger already states it) and
|
|
159
|
+
* is single-select, so give it `isMulti: false` and a `placeholder` that
|
|
160
|
+
* reads as the unfiltered state ("All price lists").
|
|
161
|
+
*
|
|
162
|
+
* `hidden: true` wins over this: a tab that pins the filter must not leave
|
|
163
|
+
* a select next to it claiming otherwise.
|
|
164
|
+
*
|
|
165
|
+
* @default 'drawer'
|
|
151
166
|
*/
|
|
152
|
-
|
|
167
|
+
position?: "bar" | "drawer";
|
|
168
|
+
/**
|
|
169
|
+
* props required for the UI component.
|
|
170
|
+
*
|
|
171
|
+
* Either a fixed list of `options` — statuses, kinds, anything the app
|
|
172
|
+
* already knows — or a `resource` the options are fetched from.
|
|
173
|
+
*/
|
|
174
|
+
props: ({
|
|
175
|
+
/**
|
|
176
|
+
* The options to choose from. An option can be hidden from the UI
|
|
177
|
+
* and still be accepted in the query, e.g. a status that is only
|
|
178
|
+
* ever set through a predefined link.
|
|
179
|
+
*/
|
|
180
|
+
options: Array<{
|
|
181
|
+
label: string;
|
|
182
|
+
value: string;
|
|
183
|
+
isHidden?: boolean;
|
|
184
|
+
}>;
|
|
185
|
+
} | (Pick<InputResourceGroupProps, "resource" | "fieldForLabel" | "fieldForValue" | "searchBy" | "sortBy" | "filters" | "hideWhenSingleItem"> & {
|
|
153
186
|
/**
|
|
154
187
|
* How many options to load upfront. Capped at 25 by the Core API, which
|
|
155
188
|
* is why `searchBy` should be set when more options exist.
|
|
156
189
|
* @default 25
|
|
157
190
|
*/
|
|
158
191
|
limit?: number;
|
|
192
|
+
})) & {
|
|
159
193
|
placeholder?: string;
|
|
160
194
|
isClearable?: boolean;
|
|
161
195
|
/**
|
|
@@ -212,6 +246,15 @@ export type FiltersInstructionItem = FilterItemOptions | FilterItemTextSearch |
|
|
|
212
246
|
export type FiltersInstructions = FiltersInstructionItem[];
|
|
213
247
|
export declare function isItemOptions(item: FiltersInstructionItem): item is FilterItemOptions;
|
|
214
248
|
export declare function isTextSearch(item: FiltersInstructionItem): item is FilterItemTextSearch;
|
|
249
|
+
/**
|
|
250
|
+
* The predicate of the free text filter shown in the search bar, if any.
|
|
251
|
+
*
|
|
252
|
+
* Not simply the first `textSearch` instruction: apps also declare `textSearch`
|
|
253
|
+
* items for predicates they only want whitelisted (hidden ones driving tabs, for
|
|
254
|
+
* instance), and those can come first. There is at most one `searchBar` in a set
|
|
255
|
+
* of instructions, so this is unambiguous.
|
|
256
|
+
*/
|
|
257
|
+
export declare function getSearchBarPredicate(instructions: FiltersInstructions): string | undefined;
|
|
215
258
|
export declare function isCurrencyRange(item: FiltersInstructionItem): item is FilterItemCurrencyRange;
|
|
216
259
|
export declare function isGroupedPredicates(item: FiltersInstructionItem): item is FilterItemGroupedPredicates;
|
|
217
260
|
/**
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { InputSelectValue } from '../../forms/InputSelect';
|
|
2
|
+
import { FilterItemOptions } from './types';
|
|
3
|
+
type SelectRender = Extract<FilterItemOptions["render"], {
|
|
4
|
+
component: "inputSelect";
|
|
5
|
+
}>;
|
|
6
|
+
/** The props of a select whose options come from a resource, not a fixed list. */
|
|
7
|
+
export type ResourceSelectProps = Exclude<SelectRender["props"], {
|
|
8
|
+
options: unknown;
|
|
9
|
+
}>;
|
|
10
|
+
/** Core caps `pageSize` at 25, so this is also the most we can load in one go. */
|
|
11
|
+
export declare const defaultOptionsLimit = 10;
|
|
12
|
+
export interface ResourceSelectOptions {
|
|
13
|
+
/** Options to hand to the select: the first page, plus anything selected. */
|
|
14
|
+
initialValues: InputSelectValue[];
|
|
15
|
+
/** The first page is still loading. */
|
|
16
|
+
isLoading: boolean;
|
|
17
|
+
/** How many records exist in total, once known. */
|
|
18
|
+
recordCount?: number;
|
|
19
|
+
/** Whether the labels of the current selection have been resolved. */
|
|
20
|
+
hasResolvedSelection: boolean;
|
|
21
|
+
/** Server-side search, when the instruction sets `searchBy`. */
|
|
22
|
+
loadAsyncValues?: (hint: string) => Promise<InputSelectValue[]>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Loads the options of a resource-backed filter select.
|
|
26
|
+
*
|
|
27
|
+
* Shared by the two places such a select is rendered — the filters drawer and,
|
|
28
|
+
* for a filter promoted with `position: "bar"`, the filters bar — so that both
|
|
29
|
+
* fetch the same way and a value picked in one resolves its label in the other.
|
|
30
|
+
*/
|
|
31
|
+
export declare function useResourceSelectOptions({ props, selectedValues, }: {
|
|
32
|
+
props: ResourceSelectProps;
|
|
33
|
+
selectedValues: string[];
|
|
34
|
+
}): ResourceSelectOptions;
|
|
35
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FilterItemOptions, FiltersInstructions } from './types';
|
|
1
|
+
import { FilterItemOptions, FiltersInstructionItem, FiltersInstructions } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* Show the filter label with the counter for selected options
|
|
4
4
|
* or just the total of available options when nothing is selected
|
|
@@ -27,3 +27,20 @@ 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;
|
|
40
|
+
/**
|
|
41
|
+
* Whether a filter is promoted out of the drawer and into `FiltersBar`.
|
|
42
|
+
*
|
|
43
|
+
* `hidden` wins: a tab that pins the predicate must not leave a select in the bar
|
|
44
|
+
* claiming otherwise.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isBarFilter(instructionItem: FiltersInstructionItem): boolean;
|
|
@@ -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 {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
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
|
-
*
|
|
38
|
-
*
|
|
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
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
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
|
-
*
|
|
48
|
-
*
|
|
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
|
|
54
|
-
*
|
|
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:
|
|
57
|
-
*
|
|
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?:
|
|
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 =
|
|
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
|
|
127
|
-
*
|
|
128
|
-
*
|
|
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
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commercelayer/app-elements",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.15.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
|
|
105
|
-
"build:
|
|
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 {};
|
|
File without changes
|