@zephytiju/prism-search-results 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.
- package/README.md +58 -0
- package/dist/SearchResults.d.ts +28 -0
- package/dist/SearchResults.d.ts.map +1 -0
- package/dist/SearchResults.js +36 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# PrismSearchResultsMicroUI
|
|
2
|
+
|
|
3
|
+
Platform Prism search-results micro-UI. Component id: `search-results`.
|
|
4
|
+
Published to npm as [`@zephytiju/prism-search-results`](https://www.npmjs.com/package/@zephytiju/prism-search-results).
|
|
5
|
+
|
|
6
|
+
Read-only rendering surface for the entity-search contract family: it consumes the channels the
|
|
7
|
+
query-box publishes and never talks to Lattice itself. Render order is fixed — error alert with a
|
|
8
|
+
Retry button, busy-without-results skeletons, guided empty state, then the `{N} MATCHES` header
|
|
9
|
+
and entity cards (dimmed via opacity while a follow-up search is in flight). Composed
|
|
10
|
+
applications (for example Guanlan) consume it as-is; the component is platform-owned.
|
|
11
|
+
|
|
12
|
+
## Channel contract
|
|
13
|
+
|
|
14
|
+
| Direction | Kind | Id | Payload |
|
|
15
|
+
| --- | --- | --- | --- |
|
|
16
|
+
| consumes | state | `query-box.entity-results` | `EntityResultsProjection \| null` |
|
|
17
|
+
| consumes | state | `query-box.search-status` | `SearchStatus` (imported from `@zephytiju/prism-query-box`) |
|
|
18
|
+
| publishes | state | `search-results.selected-entity` | `{ id, ontologyInterface: "IEntitySummary", label }` on card click |
|
|
19
|
+
| emits | event | `query-box.search-retry` | `null` — the error Retry button asks the query-box to re-run its last request |
|
|
20
|
+
|
|
21
|
+
Channel ids are string literals at every call-site so the build-time channel-graph scanner can
|
|
22
|
+
derive the graph. Channel reads use `usePrismStateValue`; the single publication is setter-only.
|
|
23
|
+
|
|
24
|
+
## Audit rule
|
|
25
|
+
|
|
26
|
+
Entity search is NOT audit-worthy. This component emits NO audit event. The only event it ever
|
|
27
|
+
emits is the internal `query-box.search-retry` (an error-retry handshake inside the search
|
|
28
|
+
contract family, not an observable domain action).
|
|
29
|
+
|
|
30
|
+
## Theme
|
|
31
|
+
|
|
32
|
+
No colors are hardcoded. The component uses Mantine components without color props; the color
|
|
33
|
+
theme comes from the host runtime, which wraps the component in its `MantineProvider`. The
|
|
34
|
+
in-flight dimming uses opacity, not a color.
|
|
35
|
+
|
|
36
|
+
## Local development
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
npm install
|
|
40
|
+
npm run typecheck
|
|
41
|
+
npm test
|
|
42
|
+
npm run dev
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`npm install` pulls the platform peers (`@zephytiju/prism-react`,
|
|
46
|
+
`@zephytiju/prism-query-box`, `@zephytiju/lattice-common-interfaces`) from the npm
|
|
47
|
+
registry, along with the host-side peer dependencies (`react`, `react-dom`,
|
|
48
|
+
`@mantine/core`). When consuming the published package, install it directly
|
|
49
|
+
(`npm install @zephytiju/prism-search-results`) and provide those peer dependencies in
|
|
50
|
+
the host application.
|
|
51
|
+
|
|
52
|
+
The demo (`npm run dev`) plays the host: buttons publish sample results, busy, idle, and error
|
|
53
|
+
states onto the query-box channels so every render branch can be inspected in the browser.
|
|
54
|
+
|
|
55
|
+
## Design record
|
|
56
|
+
|
|
57
|
+
https://qcnwge0wy4s0.feishu.cn/wiki/K40nwA5TZiUE7Nk5hK6cE0W8nTe — §7 (channel contracts) and
|
|
58
|
+
§8 (Lattice transport and interface clients).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { EntityReference } from "@zephytiju/lattice-common-interfaces";
|
|
2
|
+
/**
|
|
3
|
+
* Payload published on "search-results.selected-entity" when an entity card is
|
|
4
|
+
* clicked — an EntityReference pinned to the IEntitySummary interface.
|
|
5
|
+
*/
|
|
6
|
+
export type SelectedEntity = EntityReference & {
|
|
7
|
+
readonly ontologyInterface: "IEntitySummary";
|
|
8
|
+
readonly label: string;
|
|
9
|
+
};
|
|
10
|
+
export interface SearchResultsProps {
|
|
11
|
+
/** Guidance copy for the pre-search empty state. */
|
|
12
|
+
readonly emptyStateHint?: string;
|
|
13
|
+
/** Copy for the error alert title. */
|
|
14
|
+
readonly errorTitle?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Platform Prism search-results micro-UI (component id "search-results").
|
|
18
|
+
*
|
|
19
|
+
* Read-only consumer of the query-box channels; makes NO Lattice calls. Render
|
|
20
|
+
* order: error alert (with retry), busy-without-results skeletons, guided empty
|
|
21
|
+
* state, then the "{N} MATCHES" header and entity cards — dimmed via opacity
|
|
22
|
+
* while a follow-up search is in flight. Selecting a card publishes
|
|
23
|
+
* "search-results.selected-entity"; the error Retry button emits the internal
|
|
24
|
+
* "query-box.search-retry" event so the query-box re-runs its last request.
|
|
25
|
+
* Entity search is NOT audit-worthy: no audit event is ever emitted.
|
|
26
|
+
*/
|
|
27
|
+
export declare function SearchResults({ emptyStateHint, errorTitle, }: SearchResultsProps): import("react").JSX.Element;
|
|
28
|
+
//# sourceMappingURL=SearchResults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchResults.d.ts","sourceRoot":"","sources":["../src/SearchResults.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAA2B,MAAM,sCAAsC,CAAC;AAIrG;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG;IAC7C,QAAQ,CAAC,iBAAiB,EAAE,gBAAgB,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,oDAAoD;IACpD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,sCAAsC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,EAC5B,cAAyC,EACzC,UAAgC,GACjC,EAAE,kBAAkB,+BA6FpB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Alert, Badge, Button, Card, Group, Skeleton, Stack, Text } from "@mantine/core";
|
|
3
|
+
import { emitPrismEvent, usePrismStateSetter, usePrismStateValue } from "@zephytiju/prism-react";
|
|
4
|
+
const DEFAULT_EMPTY_STATE_HINT = "Enter a query in the search box above to find entities. Apply filters to narrow the result set.";
|
|
5
|
+
const DEFAULT_ERROR_TITLE = "Search failed";
|
|
6
|
+
/**
|
|
7
|
+
* Platform Prism search-results micro-UI (component id "search-results").
|
|
8
|
+
*
|
|
9
|
+
* Read-only consumer of the query-box channels; makes NO Lattice calls. Render
|
|
10
|
+
* order: error alert (with retry), busy-without-results skeletons, guided empty
|
|
11
|
+
* state, then the "{N} MATCHES" header and entity cards — dimmed via opacity
|
|
12
|
+
* while a follow-up search is in flight. Selecting a card publishes
|
|
13
|
+
* "search-results.selected-entity"; the error Retry button emits the internal
|
|
14
|
+
* "query-box.search-retry" event so the query-box re-runs its last request.
|
|
15
|
+
* Entity search is NOT audit-worthy: no audit event is ever emitted.
|
|
16
|
+
*/
|
|
17
|
+
export function SearchResults({ emptyStateHint = DEFAULT_EMPTY_STATE_HINT, errorTitle = DEFAULT_ERROR_TITLE, }) {
|
|
18
|
+
const results = usePrismStateValue("query-box.entity-results");
|
|
19
|
+
const status = usePrismStateValue("query-box.search-status");
|
|
20
|
+
const publishSelectedEntity = usePrismStateSetter("search-results.selected-entity");
|
|
21
|
+
if (status?.phase === "error") {
|
|
22
|
+
return (_jsx(Alert, { variant: "light", title: errorTitle, "data-testid": "search-results-error", children: _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", "data-testid": "search-results-error-message", children: status.message }), _jsx(Group, { children: _jsx(Button, { variant: "default", "data-testid": "search-results-retry", onClick: () => emitPrismEvent("query-box.search-retry", null), children: "Retry" }) })] }) }));
|
|
23
|
+
}
|
|
24
|
+
if (status?.phase === "busy" && results === null) {
|
|
25
|
+
return (_jsx(Stack, { gap: "sm", "data-testid": "search-results-loading", "aria-busy": "true", children: [0, 1, 2].map((row) => (_jsx(Skeleton, { height: 72, radius: "md" }, row))) }));
|
|
26
|
+
}
|
|
27
|
+
if (results === null) {
|
|
28
|
+
return (_jsx(Card, { withBorder: true, "data-testid": "search-results-empty", children: _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { fw: 500, children: "No results yet" }), _jsx(Text, { size: "sm", children: emptyStateHint })] }) }));
|
|
29
|
+
}
|
|
30
|
+
const inFlight = status?.phase === "busy";
|
|
31
|
+
return (_jsxs(Stack, { gap: "sm", "data-testid": "search-results-list", style: { opacity: inFlight ? 0.5 : 1 }, children: [_jsxs(Group, { justify: "space-between", children: [_jsxs(Text, { fw: 600, "data-testid": "search-results-count", children: [results.resultIds.length, " MATCHES"] }), results.nextCursor !== undefined ? (_jsx(Badge, { variant: "light", size: "sm", children: "more available" })) : null] }), results.items.map((item) => (_jsx(Card, { withBorder: true, "data-testid": `search-result-card-${item.id}`, style: { cursor: "pointer" }, onClick: () => publishSelectedEntity({
|
|
32
|
+
id: item.id,
|
|
33
|
+
ontologyInterface: "IEntitySummary",
|
|
34
|
+
label: item.label,
|
|
35
|
+
}), children: _jsxs(Group, { justify: "space-between", wrap: "nowrap", children: [_jsxs("div", { children: [_jsx(Text, { fw: 500, children: item.label }), _jsx(Text, { size: "sm", children: item.id })] }), _jsx(Badge, { variant: "light", children: item.type })] }) }, item.id)))] }));
|
|
36
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SearchResults } from "./SearchResults.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zephytiju/prism-search-results",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Platform Prism search-results micro-UI (component id \"search-results\"): renders the entity-results and search-status channels published by the query-box — empty, busy, error-with-retry, and match-list states — and publishes the selected entity. No Lattice calls.",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": { "access": "public" },
|
|
16
|
+
"files": ["dist"],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"dev": "vite --host 127.0.0.1",
|
|
19
|
+
"build": "tsc -p tsconfig.build.json",
|
|
20
|
+
"typecheck": "tsc --noEmit",
|
|
21
|
+
"test": "vitest run"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@mantine/core": "^8.1.1",
|
|
25
|
+
"@zephytiju/lattice-common-interfaces": ">=0.1.0",
|
|
26
|
+
"@zephytiju/prism-query-box": ">=0.1.0",
|
|
27
|
+
"@zephytiju/prism-react": ">=0.1.0",
|
|
28
|
+
"react": "^19.1.0",
|
|
29
|
+
"react-dom": "^19.1.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@mantine/core": "8.1.1",
|
|
33
|
+
"@testing-library/dom": "^10.4.0",
|
|
34
|
+
"@testing-library/react": "^16.1.0",
|
|
35
|
+
"@types/node": "^22.10.2",
|
|
36
|
+
"@types/react": "^19.1.0",
|
|
37
|
+
"@types/react-dom": "^19.1.0",
|
|
38
|
+
"@zephytiju/lattice-common-interfaces": "0.1.0",
|
|
39
|
+
"@zephytiju/prism-query-box": "0.1.0",
|
|
40
|
+
"@zephytiju/prism-react": "0.1.0",
|
|
41
|
+
"jsdom": "^25.0.1",
|
|
42
|
+
"react": "19.1.0",
|
|
43
|
+
"react-dom": "19.1.0",
|
|
44
|
+
"typescript": "^5.7.2",
|
|
45
|
+
"vite": "6.0.5",
|
|
46
|
+
"vitest": "^2.1.8"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=20"
|
|
50
|
+
}
|
|
51
|
+
}
|