@stapel/listings-react 0.3.1 → 0.7.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/CHANGELOG.md +122 -0
- package/MODULE.md +12 -6
- package/README.md +33 -17
- package/dist/api/generated/schema.d.ts +129 -3
- package/dist/api/generated/schema.d.ts.map +1 -1
- package/dist/api/listingsApi.d.ts +35 -22
- package/dist/api/listingsApi.d.ts.map +1 -1
- package/dist/api/listingsApi.js +17 -0
- package/dist/api/listingsApi.js.map +1 -1
- package/dist/api/types.d.ts +43 -2
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/types.js.map +1 -1
- package/dist/default/FavoritesPane.d.ts +40 -3
- package/dist/default/FavoritesPane.d.ts.map +1 -1
- package/dist/default/FavoritesPane.js +30 -18
- package/dist/default/FavoritesPane.js.map +1 -1
- package/dist/default/ListingCard.d.ts +25 -4
- package/dist/default/ListingCard.d.ts.map +1 -1
- package/dist/default/ListingCard.js +19 -12
- package/dist/default/ListingCard.js.map +1 -1
- package/dist/default/ListingComposerPage.d.ts +163 -23
- package/dist/default/ListingComposerPage.d.ts.map +1 -1
- package/dist/default/ListingComposerPage.js +85 -43
- package/dist/default/ListingComposerPage.js.map +1 -1
- package/dist/default/ListingDetailPane.d.ts +41 -4
- package/dist/default/ListingDetailPane.d.ts.map +1 -1
- package/dist/default/ListingDetailPane.js +38 -25
- package/dist/default/ListingDetailPane.js.map +1 -1
- package/dist/default/ListingPhoto.d.ts +13 -1
- package/dist/default/ListingPhoto.d.ts.map +1 -1
- package/dist/default/ListingPhoto.js +47 -9
- package/dist/default/ListingPhoto.js.map +1 -1
- package/dist/default/ListingPrice.d.ts +13 -0
- package/dist/default/ListingPrice.d.ts.map +1 -0
- package/dist/default/ListingPrice.js +60 -0
- package/dist/default/ListingPrice.js.map +1 -0
- package/dist/default/MyListingsPane.d.ts +9 -17
- package/dist/default/MyListingsPane.d.ts.map +1 -1
- package/dist/default/MyListingsPane.js +148 -63
- package/dist/default/MyListingsPane.js.map +1 -1
- package/dist/default/SignInLink.js +8 -7
- package/dist/default/SignInLink.js.map +1 -1
- package/dist/default/StatusTags.d.ts +16 -5
- package/dist/default/StatusTags.d.ts.map +1 -1
- package/dist/default/StatusTags.js +19 -13
- package/dist/default/StatusTags.js.map +1 -1
- package/dist/default/index.d.ts +15 -9
- package/dist/default/index.d.ts.map +1 -1
- package/dist/default/index.js +13 -6
- package/dist/default/index.js.map +1 -1
- package/dist/headless/Favorites.d.ts +6 -0
- package/dist/headless/Favorites.d.ts.map +1 -1
- package/dist/headless/Favorites.js +4 -0
- package/dist/headless/Favorites.js.map +1 -1
- package/dist/headless/ListingActions.d.ts +12 -0
- package/dist/headless/ListingActions.d.ts.map +1 -1
- package/dist/headless/ListingActions.js +3 -0
- package/dist/headless/ListingActions.js.map +1 -1
- package/dist/headless/ListingComposer.d.ts +23 -0
- package/dist/headless/ListingComposer.d.ts.map +1 -1
- package/dist/headless/ListingComposer.js +33 -7
- package/dist/headless/ListingComposer.js.map +1 -1
- package/dist/headless/MyListings.d.ts +27 -12
- package/dist/headless/MyListings.d.ts.map +1 -1
- package/dist/headless/MyListings.js +29 -7
- package/dist/headless/MyListings.js.map +1 -1
- package/dist/i18n/es.d.ts +6 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +28 -6
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/generated/errors.es.gen.d.ts +1 -1
- package/dist/i18n/generated/errors.es.gen.js +1 -1
- package/dist/i18n/generated/errors.gen.d.ts +6 -0
- package/dist/i18n/generated/errors.gen.d.ts.map +1 -1
- package/dist/i18n/generated/errors.gen.js +3 -0
- package/dist/i18n/generated/errors.gen.js.map +1 -1
- package/dist/i18n/generated/errors.ru.gen.d.ts +1 -1
- package/dist/i18n/generated/errors.ru.gen.js +1 -1
- package/dist/i18n/keys.d.ts +28 -4
- package/dist/i18n/keys.d.ts.map +1 -1
- package/dist/i18n/keys.js +49 -8
- package/dist/i18n/keys.js.map +1 -1
- package/dist/i18n/ru.d.ts +16 -1
- package/dist/i18n/ru.d.ts.map +1 -1
- package/dist/i18n/ru.js +40 -6
- package/dist/i18n/ru.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/model/draft.d.ts +9 -6
- package/dist/model/draft.d.ts.map +1 -1
- package/dist/model/draft.js +3 -1
- package/dist/model/draft.js.map +1 -1
- package/dist/model/features.d.ts +21 -7
- package/dist/model/features.d.ts.map +1 -1
- package/dist/model/features.js +26 -0
- package/dist/model/features.js.map +1 -1
- package/dist/model/mine.d.ts +44 -0
- package/dist/model/mine.d.ts.map +1 -0
- package/dist/model/mine.js +52 -0
- package/dist/model/mine.js.map +1 -0
- package/dist/model/mineSource.d.ts +39 -34
- package/dist/model/mineSource.d.ts.map +1 -1
- package/dist/model/mineSource.js +10 -41
- package/dist/model/mineSource.js.map +1 -1
- package/dist/model/mutations.d.ts.map +1 -1
- package/dist/model/mutations.js +11 -4
- package/dist/model/mutations.js.map +1 -1
- package/dist/model/queryKeys.d.ts +7 -2
- package/dist/model/queryKeys.d.ts.map +1 -1
- package/dist/model/queryKeys.js +2 -0
- package/dist/model/queryKeys.js.map +1 -1
- package/dist/model/status.d.ts +12 -31
- package/dist/model/status.d.ts.map +1 -1
- package/dist/model/status.js +44 -0
- package/dist/model/status.js.map +1 -1
- package/llms.txt +11 -8
- package/manifest.json +88 -14
- package/nav-manifest.json +1 -1
- package/package.json +17 -12
- package/src/analytics/generated/events.json +1 -1
- package/src/api/generated/schema.ts +129 -3
- package/src/api/listingsApi.ts +60 -21
- package/src/api/types.ts +46 -2
- package/src/default/FavoritesPane.tsx +156 -82
- package/src/default/ListingCard.tsx +88 -46
- package/src/default/ListingComposerPage.tsx +403 -187
- package/src/default/ListingDetailPane.tsx +200 -98
- package/src/default/ListingPhoto.tsx +89 -16
- package/src/default/ListingPrice.tsx +77 -0
- package/src/default/MyListingsPane.tsx +344 -222
- package/src/default/SignInLink.tsx +4 -4
- package/src/default/StatusTags.tsx +36 -18
- package/src/default/index.ts +18 -7
- package/src/headless/Favorites.tsx +10 -0
- package/src/headless/ListingActions.tsx +19 -0
- package/src/headless/ListingComposer.tsx +56 -5
- package/src/headless/MyListings.tsx +62 -22
- package/src/i18n/es.ts +36 -7
- package/src/i18n/generated/errors.es.gen.ts +1 -1
- package/src/i18n/generated/errors.gen.ts +3 -0
- package/src/i18n/generated/errors.json +9 -0
- package/src/i18n/generated/errors.ru.gen.ts +1 -1
- package/src/i18n/keys.ts +58 -9
- package/src/i18n/ru.ts +48 -7
- package/src/index.ts +16 -5
- package/src/model/draft.ts +12 -7
- package/src/model/features.ts +48 -7
- package/src/model/mine.ts +70 -0
- package/src/model/mineSource.ts +46 -41
- package/src/model/mutations.ts +11 -4
- package/src/model/queryKeys.ts +9 -2
- package/src/model/status.ts +15 -0
- package/dist/default/ErrorAlert.d.ts +0 -9
- package/dist/default/ErrorAlert.d.ts.map +0 -1
- package/dist/default/ErrorAlert.js +0 -27
- package/dist/default/ErrorAlert.js.map +0 -1
- package/dist/default/theme.d.ts +0 -25
- package/dist/default/theme.d.ts.map +0 -1
- package/dist/default/theme.js +0 -40
- package/dist/default/theme.js.map +0 -1
- package/src/default/ErrorAlert.tsx +0 -46
- package/src/default/theme.tsx +0 -67
package/src/model/mineSource.ts
CHANGED
|
@@ -1,55 +1,60 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* THE GAP
|
|
2
|
+
* THE GAP, AND THE ROUTE THAT CLOSED IT.
|
|
3
3
|
*
|
|
4
|
-
* This
|
|
5
|
-
*
|
|
4
|
+
* This file used to open "stapel-listings cannot list a person their own
|
|
5
|
+
* listings", and that was the only place in the pair where a contract was
|
|
6
|
+
* missing rather than awkward. `GET /listings/` answers `qs.published()` and
|
|
7
|
+
* takes no owner parameter (`views.ListingViewSet.get_queryset`): it returns
|
|
8
|
+
* the whole marketplace's shop window and can be narrowed to nobody. The only
|
|
9
|
+
* owner-scoped reads were `my/counters` (three integers) and `my/favorites`,
|
|
10
|
+
* so a seller's own DRAFTS were unreachable by any call the contract offered
|
|
11
|
+
* — and drafts are not indexed either, so routing around it through
|
|
12
|
+
* `@stapel/search-react`'s `owner=` would have returned the published subset
|
|
13
|
+
* and quietly called it "everything". The dashboard shipped with a
|
|
14
|
+
* host-injected source and NAMED the absence on screen, because "we cannot
|
|
15
|
+
* ask" and "you have no listings" are different sentences.
|
|
6
16
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* quietly call it "everything".
|
|
17
|
+
* **stapel-listings 0.7.0 answers it**: `GET /listings/my/listings/`, the
|
|
18
|
+
* caller's own rows in every status, `?status=` for a tab's set, the same
|
|
19
|
+
* `IDAnchorPagination` envelope the other two owner reads use. So
|
|
20
|
+
* {@link defaultMyListingsSource} is what the dashboard runs on now, and
|
|
21
|
+
* there is no failure state left to name — the missing-source error and its
|
|
22
|
+
* i18n key are gone rather than kept as a comment about a thing that no
|
|
23
|
+
* longer happens.
|
|
15
24
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* can be narrowed without a search module.
|
|
24
|
-
*
|
|
25
|
-
* Until then a host injects a {@link MyListingsSource} and the dashboard
|
|
26
|
-
* works completely; without one it shows the real counters and NAMES the
|
|
27
|
-
* absence, because "we cannot ask" and "you have no listings" are different
|
|
28
|
-
* sentences.
|
|
25
|
+
* {@link MyListingsSource} stays, as a seam and not as a workaround: a
|
|
26
|
+
* deployment that keeps its sellers' rows somewhere else (a read model, a
|
|
27
|
+
* legacy table, a host that has already fetched the page) hands one in and
|
|
28
|
+
* the dashboard renders it unchanged. What it must return is one page of the
|
|
29
|
+
* owner card — including the `moderation_status` and the `*_draft` twins,
|
|
30
|
+
* which is why the type is {@link PaginatedMyListingCards} and not the public
|
|
31
|
+
* card envelope.
|
|
29
32
|
*/
|
|
30
|
-
import {
|
|
31
|
-
import type {
|
|
33
|
+
import type { ListingsApi } from "../api/listingsApi.js";
|
|
34
|
+
import type { MyListingsParams, PaginatedMyListingCards } from "../api/types.js";
|
|
32
35
|
import type { MyListingsTab } from "./status.js";
|
|
33
|
-
import {
|
|
36
|
+
import { MY_LISTINGS_TAB_STATUSES } from "./status.js";
|
|
34
37
|
|
|
35
|
-
/** One page of the caller's own listings, however the host
|
|
38
|
+
/** One page of the caller's own listings, however the host gets them. */
|
|
36
39
|
export type MyListingsSource = (args: {
|
|
37
40
|
readonly tab: MyListingsTab;
|
|
38
|
-
readonly page:
|
|
41
|
+
readonly page: MyListingsParams;
|
|
39
42
|
readonly signal?: AbortSignal;
|
|
40
|
-
}) => Promise<
|
|
43
|
+
}) => Promise<PaginatedMyListingCards>;
|
|
41
44
|
|
|
42
45
|
/**
|
|
43
|
-
* The
|
|
46
|
+
* The source the dashboard uses unless a host replaces it: the contract's own
|
|
47
|
+
* route, narrowed to the tab's statuses.
|
|
44
48
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
49
|
+
* The tab → statuses table is `MY_LISTINGS_TAB_STATUSES`, which is a copy of
|
|
50
|
+
* the SERVER's grouping in `views.my_counters`. That is the whole point: the
|
|
51
|
+
* rows this fetches and the count on the tab beside them are the same set,
|
|
52
|
+
* asserted upstream (`tests/test_my_listings.py`) and here.
|
|
48
53
|
*/
|
|
49
|
-
export
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
54
|
+
export function defaultMyListingsSource(api: ListingsApi): MyListingsSource {
|
|
55
|
+
return ({ tab, page, signal }) =>
|
|
56
|
+
api.myListings(
|
|
57
|
+
{ ...page, status: MY_LISTINGS_TAB_STATUSES[tab] },
|
|
58
|
+
signal !== undefined ? { signal } : {}
|
|
59
|
+
);
|
|
60
|
+
}
|
package/src/model/mutations.ts
CHANGED
|
@@ -27,10 +27,13 @@ import { listingsQueryKeys } from "./queryKeys.js";
|
|
|
27
27
|
* ── The invalidation rule ──────────────────────────────────────────────────
|
|
28
28
|
*
|
|
29
29
|
* A write that can move `status` or `moderation_status` invalidates the
|
|
30
|
-
* DETAIL, the STATUS probe and the
|
|
31
|
-
* three tabs are defined by status sets (`views.my_counters`),
|
|
32
|
-
* silently moves a row from "drafts" to "active" and a dashboard
|
|
33
|
-
* refetch would show the old number beside the new row
|
|
30
|
+
* DETAIL, the STATUS probe, the COUNTERS and the owner's ROWS — the counters
|
|
31
|
+
* because their three tabs are defined by status sets (`views.my_counters`),
|
|
32
|
+
* so a publish silently moves a row from "drafts" to "active" and a dashboard
|
|
33
|
+
* that did not refetch would show the old number beside the new row; the rows
|
|
34
|
+
* for the same reason, since stapel-listings 0.7.0 gave them a route and they
|
|
35
|
+
* are narrowed by exactly those status sets. Invalidating one and not the
|
|
36
|
+
* other is the shape of the bug where the badge says 2 and the tab shows 3.
|
|
34
37
|
*
|
|
35
38
|
* Nothing here is optimistic except the favourite toggle, and that exception
|
|
36
39
|
* is argued at its own hook.
|
|
@@ -46,6 +49,7 @@ function invalidateListing(queryClient: QueryClient, id: number): void {
|
|
|
46
49
|
void queryClient.invalidateQueries({
|
|
47
50
|
queryKey: listingsQueryKeys.validateDraft(id),
|
|
48
51
|
});
|
|
52
|
+
void queryClient.invalidateQueries({ queryKey: listingsQueryKeys.allMine() });
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
/** Start a draft. The server forces `owner` and `status=draft`. */
|
|
@@ -63,6 +67,9 @@ export function useCreateDraft(): UseMutationResult<
|
|
|
63
67
|
void queryClient.invalidateQueries({
|
|
64
68
|
queryKey: listingsQueryKeys.myCounters(),
|
|
65
69
|
});
|
|
70
|
+
void queryClient.invalidateQueries({
|
|
71
|
+
queryKey: listingsQueryKeys.allMine(),
|
|
72
|
+
});
|
|
66
73
|
},
|
|
67
74
|
});
|
|
68
75
|
}
|
package/src/model/queryKeys.ts
CHANGED
|
@@ -49,12 +49,17 @@ export const listingsQueryKeys: {
|
|
|
49
49
|
myFavorites(
|
|
50
50
|
page: ListingPageKey
|
|
51
51
|
): readonly ["listings", "my", "favorites", ListingPageKey];
|
|
52
|
-
/** The owner's own rows, per tab
|
|
53
|
-
* this read goes through an injected source. */
|
|
52
|
+
/** The owner's own rows, per tab (`GET my/listings/?status=…`). */
|
|
54
53
|
mine(
|
|
55
54
|
tab: string,
|
|
56
55
|
page: ListingPageKey
|
|
57
56
|
): readonly ["listings", "my", "listings", string, ListingPageKey];
|
|
57
|
+
/** The owner's rows no tab folds in — a takedown. A sibling of `mine` and
|
|
58
|
+
* not one of its tabs, because it answers a different question and must not
|
|
59
|
+
* be evicted when a tab pages. */
|
|
60
|
+
mineUntabbed(): readonly ["listings", "my", "listings", "untabbed"];
|
|
61
|
+
/** Every owner-row page, for an invalidation after a write. */
|
|
62
|
+
allMine(): readonly ["listings", "my", "listings"];
|
|
58
63
|
/** `GET /{pk}/validate-draft/` — the dry run of a publish. */
|
|
59
64
|
validateDraft(id: number): readonly ["listings", "validate-draft", number];
|
|
60
65
|
/** Every favourites PAGE, for an invalidation after a toggle — the cursor
|
|
@@ -70,6 +75,8 @@ export const listingsQueryKeys: {
|
|
|
70
75
|
myCounters: () => [ROOT, "my", "counters"],
|
|
71
76
|
myFavorites: (page) => [ROOT, "my", "favorites", page],
|
|
72
77
|
mine: (tab, page) => [ROOT, "my", "listings", tab, page],
|
|
78
|
+
mineUntabbed: () => [ROOT, "my", "listings", "untabbed"],
|
|
79
|
+
allMine: () => [ROOT, "my", "listings"],
|
|
73
80
|
validateDraft: (id) => [ROOT, "validate-draft", id],
|
|
74
81
|
allFavorites: () => [ROOT, "my", "favorites"],
|
|
75
82
|
allLists: () => [ROOT, "list"],
|
package/src/model/status.ts
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
* asserts the whole 9 × 4 table, so a state added upstream is a red test and
|
|
30
30
|
* not a bare enum value on a page.
|
|
31
31
|
*/
|
|
32
|
+
import { LISTING_STATUSES } from "../api/types.js";
|
|
32
33
|
import type {
|
|
33
34
|
ListingLifecycleStatus,
|
|
34
35
|
ListingModerationStatus,
|
|
@@ -277,3 +278,17 @@ export function tabOf(
|
|
|
277
278
|
}
|
|
278
279
|
return undefined;
|
|
279
280
|
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* The statuses no tab folds in — `blocked`, and nothing else today.
|
|
284
|
+
*
|
|
285
|
+
* DERIVED, not written down a second time: a status added upstream and left
|
|
286
|
+
* out of the counter groupings lands here automatically and gets shown, which
|
|
287
|
+
* is the opposite of what a hardcoded `["blocked"]` would do the day it goes
|
|
288
|
+
* stale. The dashboard renders these rows OUTSIDE the tabs (see
|
|
289
|
+
* `default/MyListingsPane.tsx`) rather than folding them into one, because a
|
|
290
|
+
* tab's rows and its `my/counters` badge have to describe the same set — and
|
|
291
|
+
* `my/counters` counts a takedown in no tab at all.
|
|
292
|
+
*/
|
|
293
|
+
export const MY_LISTINGS_UNTABBED_STATUSES: readonly ListingLifecycleStatus[] =
|
|
294
|
+
LISTING_STATUSES.filter((status) => tabOf(status) === undefined);
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { CSSProperties, ReactElement, ReactNode } from "react";
|
|
2
|
-
import type { FlowErrorDisplay } from "@stapel/core";
|
|
3
|
-
export declare function ErrorAlert(props: {
|
|
4
|
-
error: FlowErrorDisplay | undefined;
|
|
5
|
-
style?: CSSProperties | undefined;
|
|
6
|
-
testId?: string | undefined;
|
|
7
|
-
action?: ReactNode;
|
|
8
|
-
}): ReactElement | null;
|
|
9
|
-
//# sourceMappingURL=ErrorAlert.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorAlert.d.ts","sourceRoot":"","sources":["../../src/default/ErrorAlert.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,wBAAgB,UAAU,CAAC,KAAK,EAAE;IAChC,KAAK,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACpC,KAAK,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,GAAG,YAAY,GAAG,IAAI,CAsBtB"}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* The one error surface this pair's default skin renders, so the split copy
|
|
4
|
-
* core produces reaches a screen the same way everywhere (mirrors the
|
|
5
|
-
* docs/notifications/workspaces etalon).
|
|
6
|
-
*
|
|
7
|
-
* Core's `describeFlowError` splits a failure into the sentence a person
|
|
8
|
-
* reads and the technical detail a support agent quotes (owner report
|
|
9
|
-
* 2026-08-09: the status used to be spliced into the sentence, ending in a
|
|
10
|
-
* bare `" (500)"`). The split only helps if a skin renders both halves at
|
|
11
|
-
* their own weights: `message` at normal weight, `detail` muted and small.
|
|
12
|
-
*
|
|
13
|
-
* `undefined` in — including a `detail` core left `undefined` because there
|
|
14
|
-
* was nothing worth quoting — renders nothing rather than an empty line.
|
|
15
|
-
*/
|
|
16
|
-
import { Alert, Typography } from "antd";
|
|
17
|
-
export function ErrorAlert(props) {
|
|
18
|
-
const { error } = props;
|
|
19
|
-
if (!error)
|
|
20
|
-
return null;
|
|
21
|
-
return (_jsx(Alert, { type: "error", showIcon: true, ...(props.style ? { style: props.style } : {}), ...(props.testId ? { "data-testid": props.testId } : {}), ...(props.action ? { action: props.action } : {}), message: error.message, ...(error.detail
|
|
22
|
-
? {
|
|
23
|
-
description: (_jsx(Typography.Text, { type: "secondary", style: { fontSize: 12 }, children: error.detail })),
|
|
24
|
-
}
|
|
25
|
-
: {}) }));
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=ErrorAlert.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorAlert.js","sourceRoot":"","sources":["../../src/default/ErrorAlert.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAIzC,MAAM,UAAU,UAAU,CAAC,KAK1B;IACC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IACxB,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,CACL,KAAC,KAAK,IACJ,IAAI,EAAC,OAAO,EACZ,QAAQ,WACJ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC3C,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KACrD,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAClD,OAAO,EAAE,KAAK,CAAC,OAAO,KAClB,CAAC,KAAK,CAAC,MAAM;YACf,CAAC,CAAC;gBACE,WAAW,EAAE,CACX,KAAC,UAAU,CAAC,IAAI,IAAC,IAAI,EAAC,WAAW,EAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,YACtD,KAAK,CAAC,MAAM,GACG,CACnB;aACF;YACH,CAAC,CAAC,EAAE,CAAC,GACP,CACH,CAAC;AACJ,CAAC"}
|
package/dist/default/theme.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { CSSProperties, ReactElement, ReactNode } from "react";
|
|
2
|
-
import type { ThemeMode } from "@stapel/tokens-antd";
|
|
3
|
-
export interface ListingsSkinThemeProps {
|
|
4
|
-
/**
|
|
5
|
-
* Light or dark. Defaults to the mode the host's document declares
|
|
6
|
-
* (`resolveThemeMode()`). Pass explicitly to pin a side.
|
|
7
|
-
*/
|
|
8
|
-
readonly mode?: ThemeMode;
|
|
9
|
-
/** Extra styles merged onto the themed root element (layout only — colors
|
|
10
|
-
* come from the mode). */
|
|
11
|
-
readonly style?: CSSProperties;
|
|
12
|
-
readonly children: ReactNode;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* `<ListingsSkinTheme/>` — the self-theming wrapper of
|
|
16
|
-
* `@stapel/listings-react/default`. Standalone use is supported (wrap any
|
|
17
|
-
* composition of the skin's parts once); the shipped surfaces
|
|
18
|
-
* (`ListingCard`, `ListingDetailPane`, `ListingComposerPage`,
|
|
19
|
-
* `MyListingsPane`, `FavoritesPane`)
|
|
20
|
-
* each already wrap themselves, and nested antd
|
|
21
|
-
* `ConfigProvider`s merge, so composing them under one `ListingsSkinTheme`
|
|
22
|
-
* stays correct.
|
|
23
|
-
*/
|
|
24
|
-
export declare function ListingsSkinTheme(props: ListingsSkinThemeProps): ReactElement;
|
|
25
|
-
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/default/theme.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAOpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B;8BAC0B;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,CAmB7E"}
|
package/dist/default/theme.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* The default skin's INTERNAL theme provider — every `/default` surface wraps
|
|
4
|
-
* itself in this, so the skin is readable no matter what the host supplies
|
|
5
|
-
* (tracker #26: a skin set with no internal provider once inherited a theme
|
|
6
|
-
* bridge serving light-mode values inside a dark document — text on
|
|
7
|
-
* background at 1.00:1). The theme derives from `@stapel/tokens` via
|
|
8
|
-
* `@stapel/tokens-antd`'s `toAntdThemeConfig(mode)`; `mode` defaults to what
|
|
9
|
-
* the HOST's document declares (`resolveThemeMode()` — the `data-theme`
|
|
10
|
-
* attribute `tokens.css` keys its dark block on), never to a hardcoded side.
|
|
11
|
-
*
|
|
12
|
-
* This is also what "override styles" means for this pair: a storefront
|
|
13
|
-
* retheming through the §68 token JSON regenerates its `--stapel-*` custom
|
|
14
|
-
* properties and the result page follows with zero code — a far better deal
|
|
15
|
-
* than a prop-per-colour API, and the reason the skin has none.
|
|
16
|
-
*/
|
|
17
|
-
import { useMemo } from "react";
|
|
18
|
-
import { ConfigProvider } from "antd";
|
|
19
|
-
import { resolveThemeMode, toAntdTheme, toAntdThemeConfig, } from "@stapel/tokens-antd";
|
|
20
|
-
/**
|
|
21
|
-
* `<ListingsSkinTheme/>` — the self-theming wrapper of
|
|
22
|
-
* `@stapel/listings-react/default`. Standalone use is supported (wrap any
|
|
23
|
-
* composition of the skin's parts once); the shipped surfaces
|
|
24
|
-
* (`ListingCard`, `ListingDetailPane`, `ListingComposerPage`,
|
|
25
|
-
* `MyListingsPane`, `FavoritesPane`)
|
|
26
|
-
* each already wrap themselves, and nested antd
|
|
27
|
-
* `ConfigProvider`s merge, so composing them under one `ListingsSkinTheme`
|
|
28
|
-
* stays correct.
|
|
29
|
-
*/
|
|
30
|
-
export function ListingsSkinTheme(props) {
|
|
31
|
-
const mode = props.mode ?? resolveThemeMode();
|
|
32
|
-
const theme = useMemo(() => toAntdThemeConfig(mode), [mode]);
|
|
33
|
-
const token = useMemo(() => toAntdTheme(mode), [mode]);
|
|
34
|
-
return (_jsx(ConfigProvider, { theme: theme, children: _jsx("div", { "data-listings-skin-root": true, "data-listings-skin-mode": mode, style: {
|
|
35
|
-
color: token.colorText,
|
|
36
|
-
backgroundColor: token.colorBgContainer,
|
|
37
|
-
...props.style,
|
|
38
|
-
}, children: props.children }) }));
|
|
39
|
-
}
|
|
40
|
-
//# sourceMappingURL=theme.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/default/theme.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AACtC,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAe7B;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAA6B;IAC7D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,gBAAgB,EAAE,CAAC;IAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACvD,OAAO,CACL,KAAC,cAAc,IAAC,KAAK,EAAE,KAAK,YAC1B,0EAE2B,IAAI,EAC7B,KAAK,EAAE;gBACL,KAAK,EAAE,KAAK,CAAC,SAAS;gBACtB,eAAe,EAAE,KAAK,CAAC,gBAAgB;gBACvC,GAAG,KAAK,CAAC,KAAK;aACf,YAEA,KAAK,CAAC,QAAQ,GACX,GACS,CAClB,CAAC;AACJ,CAAC"}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The one error surface this pair's default skin renders, so the split copy
|
|
3
|
-
* core produces reaches a screen the same way everywhere (mirrors the
|
|
4
|
-
* docs/notifications/workspaces etalon).
|
|
5
|
-
*
|
|
6
|
-
* Core's `describeFlowError` splits a failure into the sentence a person
|
|
7
|
-
* reads and the technical detail a support agent quotes (owner report
|
|
8
|
-
* 2026-08-09: the status used to be spliced into the sentence, ending in a
|
|
9
|
-
* bare `" (500)"`). The split only helps if a skin renders both halves at
|
|
10
|
-
* their own weights: `message` at normal weight, `detail` muted and small.
|
|
11
|
-
*
|
|
12
|
-
* `undefined` in — including a `detail` core left `undefined` because there
|
|
13
|
-
* was nothing worth quoting — renders nothing rather than an empty line.
|
|
14
|
-
*/
|
|
15
|
-
import { Alert, Typography } from "antd";
|
|
16
|
-
import type { CSSProperties, ReactElement, ReactNode } from "react";
|
|
17
|
-
import type { FlowErrorDisplay } from "@stapel/core";
|
|
18
|
-
|
|
19
|
-
export function ErrorAlert(props: {
|
|
20
|
-
error: FlowErrorDisplay | undefined;
|
|
21
|
-
style?: CSSProperties | undefined;
|
|
22
|
-
testId?: string | undefined;
|
|
23
|
-
action?: ReactNode;
|
|
24
|
-
}): ReactElement | null {
|
|
25
|
-
const { error } = props;
|
|
26
|
-
if (!error) return null;
|
|
27
|
-
return (
|
|
28
|
-
<Alert
|
|
29
|
-
type="error"
|
|
30
|
-
showIcon
|
|
31
|
-
{...(props.style ? { style: props.style } : {})}
|
|
32
|
-
{...(props.testId ? { "data-testid": props.testId } : {})}
|
|
33
|
-
{...(props.action ? { action: props.action } : {})}
|
|
34
|
-
message={error.message}
|
|
35
|
-
{...(error.detail
|
|
36
|
-
? {
|
|
37
|
-
description: (
|
|
38
|
-
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
|
39
|
-
{error.detail}
|
|
40
|
-
</Typography.Text>
|
|
41
|
-
),
|
|
42
|
-
}
|
|
43
|
-
: {})}
|
|
44
|
-
/>
|
|
45
|
-
);
|
|
46
|
-
}
|
package/src/default/theme.tsx
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The default skin's INTERNAL theme provider — every `/default` surface wraps
|
|
3
|
-
* itself in this, so the skin is readable no matter what the host supplies
|
|
4
|
-
* (tracker #26: a skin set with no internal provider once inherited a theme
|
|
5
|
-
* bridge serving light-mode values inside a dark document — text on
|
|
6
|
-
* background at 1.00:1). The theme derives from `@stapel/tokens` via
|
|
7
|
-
* `@stapel/tokens-antd`'s `toAntdThemeConfig(mode)`; `mode` defaults to what
|
|
8
|
-
* the HOST's document declares (`resolveThemeMode()` — the `data-theme`
|
|
9
|
-
* attribute `tokens.css` keys its dark block on), never to a hardcoded side.
|
|
10
|
-
*
|
|
11
|
-
* This is also what "override styles" means for this pair: a storefront
|
|
12
|
-
* retheming through the §68 token JSON regenerates its `--stapel-*` custom
|
|
13
|
-
* properties and the result page follows with zero code — a far better deal
|
|
14
|
-
* than a prop-per-colour API, and the reason the skin has none.
|
|
15
|
-
*/
|
|
16
|
-
import { useMemo } from "react";
|
|
17
|
-
import type { CSSProperties, ReactElement, ReactNode } from "react";
|
|
18
|
-
import { ConfigProvider } from "antd";
|
|
19
|
-
import {
|
|
20
|
-
resolveThemeMode,
|
|
21
|
-
toAntdTheme,
|
|
22
|
-
toAntdThemeConfig,
|
|
23
|
-
} from "@stapel/tokens-antd";
|
|
24
|
-
import type { ThemeMode } from "@stapel/tokens-antd";
|
|
25
|
-
|
|
26
|
-
export interface ListingsSkinThemeProps {
|
|
27
|
-
/**
|
|
28
|
-
* Light or dark. Defaults to the mode the host's document declares
|
|
29
|
-
* (`resolveThemeMode()`). Pass explicitly to pin a side.
|
|
30
|
-
*/
|
|
31
|
-
readonly mode?: ThemeMode;
|
|
32
|
-
/** Extra styles merged onto the themed root element (layout only — colors
|
|
33
|
-
* come from the mode). */
|
|
34
|
-
readonly style?: CSSProperties;
|
|
35
|
-
readonly children: ReactNode;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* `<ListingsSkinTheme/>` — the self-theming wrapper of
|
|
40
|
-
* `@stapel/listings-react/default`. Standalone use is supported (wrap any
|
|
41
|
-
* composition of the skin's parts once); the shipped surfaces
|
|
42
|
-
* (`ListingCard`, `ListingDetailPane`, `ListingComposerPage`,
|
|
43
|
-
* `MyListingsPane`, `FavoritesPane`)
|
|
44
|
-
* each already wrap themselves, and nested antd
|
|
45
|
-
* `ConfigProvider`s merge, so composing them under one `ListingsSkinTheme`
|
|
46
|
-
* stays correct.
|
|
47
|
-
*/
|
|
48
|
-
export function ListingsSkinTheme(props: ListingsSkinThemeProps): ReactElement {
|
|
49
|
-
const mode = props.mode ?? resolveThemeMode();
|
|
50
|
-
const theme = useMemo(() => toAntdThemeConfig(mode), [mode]);
|
|
51
|
-
const token = useMemo(() => toAntdTheme(mode), [mode]);
|
|
52
|
-
return (
|
|
53
|
-
<ConfigProvider theme={theme}>
|
|
54
|
-
<div
|
|
55
|
-
data-listings-skin-root
|
|
56
|
-
data-listings-skin-mode={mode}
|
|
57
|
-
style={{
|
|
58
|
-
color: token.colorText,
|
|
59
|
-
backgroundColor: token.colorBgContainer,
|
|
60
|
-
...props.style,
|
|
61
|
-
}}
|
|
62
|
-
>
|
|
63
|
-
{props.children}
|
|
64
|
-
</div>
|
|
65
|
-
</ConfigProvider>
|
|
66
|
-
);
|
|
67
|
-
}
|