uhc-portal-components-react 0.1.37 → 0.1.39

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 CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.1.39
6
+
7
+ - Keep clinical field labels unique to their inputs when speech controls are
8
+ rendered. Microphone buttons now expose only their action as the accessible
9
+ name while retaining the target field in the hover title.
10
+
11
+ ## 0.1.38
12
+
13
+ - Add a brand-neutral subject communication center that merges messages,
14
+ voice messages, internet calls and appointment notices behind accessible
15
+ All, Messages, Calls and Emergency filters.
16
+
5
17
  - Add a portal-owned clinical speech-input provider. Schema-backed IPS text
6
18
  fields now reflect the shared model state, append editable transcripts and
7
19
  reuse the existing explicit terminology-candidate selection flow. A shared
@@ -79,5 +79,5 @@ export function ClinicalSpeechInputButton({ resourceType, claim, locale, fieldLa
79
79
  setBusy(false);
80
80
  }
81
81
  };
82
- return _jsxs("span", { className: "uhcp-clinical-speech-control", children: [_jsx("button", { type: "button", className: "uhcp-clinical-speech-button", "aria-label": `${actionLabel}: ${fieldLabel}`, title: actionLabel, disabled: !ready || busy, "aria-pressed": busy, onClick: () => { void transcribe(); }, children: _jsx("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", focusable: "false", children: _jsx("path", { d: "M12 14a3 3 0 0 0 3-3V5a3 3 0 1 0-6 0v6a3 3 0 0 0 3 3Zm-5-3a1 1 0 1 0-2 0 7 7 0 0 0 6 6.92V21H8a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2h-3v-3.08A7 7 0 0 0 19 11a1 1 0 1 0-2 0 5 5 0 0 1-10 0Z" }) }) }), failed ? _jsx("small", { role: "alert", children: capability.labels.failed ?? capability.labels.unavailable }) : null] });
82
+ return _jsxs("span", { className: "uhcp-clinical-speech-control", children: [_jsx("button", { type: "button", className: "uhcp-clinical-speech-button", "aria-label": actionLabel, title: `${actionLabel}: ${fieldLabel}`, disabled: !ready || busy, "aria-pressed": busy, onClick: () => { void transcribe(); }, children: _jsx("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", focusable: "false", children: _jsx("path", { d: "M12 14a3 3 0 0 0 3-3V5a3 3 0 1 0-6 0v6a3 3 0 0 0 3 3Zm-5-3a1 1 0 1 0-2 0 7 7 0 0 0 6 6.92V21H8a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2h-3v-3.08A7 7 0 0 0 19 11a1 1 0 1 0-2 0 5 5 0 0 1-10 0Z" }) }) }), failed ? _jsx("small", { role: "alert", children: capability.labels.failed ?? capability.labels.unavailable }) : null] });
83
83
  }
@@ -0,0 +1,26 @@
1
+ import { type ReactNode } from 'react';
2
+ export type SubjectCommunicationKind = 'message' | 'audio' | 'audio-call' | 'video-call' | 'appointment';
3
+ export type SubjectCommunicationCategory = 'emergency' | 'care' | 'other';
4
+ export type SubjectCommunicationFilter = 'all' | 'messages' | 'calls' | 'emergency';
5
+ export type SubjectCommunicationItem = Readonly<{
6
+ id: string;
7
+ kind: SubjectCommunicationKind;
8
+ category: SubjectCommunicationCategory;
9
+ title: string;
10
+ summary?: string;
11
+ timestamp?: string;
12
+ status?: string;
13
+ action?: ReactNode;
14
+ }>;
15
+ export type SubjectCommunicationCenterCopy = Readonly<{
16
+ heading(subjectLabel: string): string;
17
+ filters: Readonly<Record<SubjectCommunicationFilter, string>>;
18
+ empty: string;
19
+ }>;
20
+ /** Brand-neutral, subject-scoped message and internet-call timeline for personal portals. */
21
+ export declare function SubjectCommunicationCenter({ subjectLabel, items, copy }: Readonly<{
22
+ subjectLabel: string;
23
+ items: readonly SubjectCommunicationItem[];
24
+ copy?: SubjectCommunicationCenterCopy;
25
+ }>): import("react").JSX.Element;
26
+ //# sourceMappingURL=SubjectCommunicationCenter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubjectCommunicationCenter.d.ts","sourceRoot":"","sources":["../src/SubjectCommunicationCenter.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAA;AAEzD,MAAM,MAAM,wBAAwB,GAAG,SAAS,GAAG,OAAO,GAAG,YAAY,GAAG,YAAY,GAAG,aAAa,CAAA;AACxG,MAAM,MAAM,4BAA4B,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,CAAA;AACzE,MAAM,MAAM,0BAA0B,GAAG,KAAK,GAAG,UAAU,GAAG,OAAO,GAAG,WAAW,CAAA;AAEnF,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,wBAAwB,CAAA;IAC9B,QAAQ,EAAE,4BAA4B,CAAA;IACtC,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB,CAAC,CAAA;AAEF,MAAM,MAAM,8BAA8B,GAAG,QAAQ,CAAC;IACpD,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAA;IACrC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAAC,CAAA;IAC7D,KAAK,EAAE,MAAM,CAAA;CACd,CAAC,CAAA;AAUF,6FAA6F;AAC7F,wBAAgB,0BAA0B,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,IAAmB,EAAE,EAAE,QAAQ,CAAC;IAChG,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,SAAS,wBAAwB,EAAE,CAAA;IAC1C,IAAI,CAAC,EAAE,8BAA8B,CAAA;CACtC,CAAC,+BAsBD"}
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useState } from 'react';
3
+ const DEFAULT_COPY = {
4
+ heading: subjectLabel => `Communications for ${subjectLabel}`,
5
+ filters: { all: 'All', messages: 'Messages', calls: 'Calls', emergency: 'Emergency' },
6
+ empty: 'There are no communications in this view.',
7
+ };
8
+ const FILTERS = ['all', 'messages', 'calls', 'emergency'];
9
+ /** Brand-neutral, subject-scoped message and internet-call timeline for personal portals. */
10
+ export function SubjectCommunicationCenter({ subjectLabel, items, copy = DEFAULT_COPY }) {
11
+ const [filter, setFilter] = useState('all');
12
+ const visibleItems = useMemo(() => items.filter(item => matchesFilter(item, filter)), [filter, items]);
13
+ return _jsxs("section", { className: "subject-communication-center", "aria-labelledby": "subject-communication-center-title", children: [_jsx("h2", { id: "subject-communication-center-title", children: copy.heading(subjectLabel) }), _jsx("div", { className: "subject-communication-filters", "aria-label": copy.heading(subjectLabel), children: FILTERS.map(value => _jsx("button", { type: "button", "aria-pressed": filter === value, onClick: () => setFilter(value), children: copy.filters[value] }, value)) }), visibleItems.length === 0 ? _jsx("p", { className: "subject-communication-empty", children: copy.empty }) : _jsx("ol", { className: "subject-communication-list", children: visibleItems.map(item => _jsxs("li", { "data-kind": item.kind, "data-category": item.category, children: [_jsxs("div", { children: [_jsx("strong", { children: item.title }), item.summary ? _jsx("p", { children: item.summary }) : null] }), _jsxs("div", { className: "subject-communication-meta", children: [item.timestamp ? _jsx("time", { dateTime: item.timestamp, children: item.timestamp }) : null, item.status ? _jsx("span", { children: item.status }) : null, item.action] })] }, item.id)) })] });
14
+ }
15
+ function matchesFilter(item, filter) {
16
+ if (filter === 'all')
17
+ return true;
18
+ if (filter === 'emergency')
19
+ return item.category === 'emergency';
20
+ if (filter === 'calls')
21
+ return item.kind === 'audio-call' || item.kind === 'video-call';
22
+ return item.kind === 'message' || item.kind === 'audio' || item.kind === 'appointment';
23
+ }
package/dist/index.d.ts CHANGED
@@ -30,4 +30,5 @@ export * from './IdentityEvidenceDocumentPanel.js';
30
30
  export * from './IdentityEvidenceDeclarationForm.js';
31
31
  export * from './AnimalIdentityOnboarding.js';
32
32
  export * from './EmergencyTaskHub.js';
33
+ export * from './SubjectCommunicationCenter.js';
33
34
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,uBAAuB,CAAA;AACrC,cAAc,wCAAwC,CAAA;AACtD,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,0BAA0B,CAAA;AACxC,cAAc,2BAA2B,CAAA;AACzC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,wBAAwB,CAAA;AACtC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,0CAA0C,CAAA;AACxD,cAAc,kCAAkC,CAAA;AAChD,cAAc,0BAA0B,CAAA;AACxC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,oCAAoC,CAAA;AAClD,cAAc,sCAAsC,CAAA;AACpD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uBAAuB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,uBAAuB,CAAA;AACrC,cAAc,wCAAwC,CAAA;AACtD,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,0BAA0B,CAAA;AACxC,cAAc,2BAA2B,CAAA;AACzC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,wBAAwB,CAAA;AACtC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,0CAA0C,CAAA;AACxD,cAAc,kCAAkC,CAAA;AAChD,cAAc,0BAA0B,CAAA;AACxC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,oCAAoC,CAAA;AAClD,cAAc,sCAAsC,CAAA;AACpD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uBAAuB,CAAA;AACrC,cAAc,iCAAiC,CAAA"}
package/dist/index.js CHANGED
@@ -30,3 +30,4 @@ export * from './IdentityEvidenceDocumentPanel.js';
30
30
  export * from './IdentityEvidenceDeclarationForm.js';
31
31
  export * from './AnimalIdentityOnboarding.js';
32
32
  export * from './EmergencyTaskHub.js';
33
+ export * from './SubjectCommunicationCenter.js';
package/dist/styles.css CHANGED
@@ -679,3 +679,13 @@ html[data-theme='dark'] .uhcp-brand-artwork-dark { display: block !important; }
679
679
  .uhcp-subject-identity-card dt { color: var(--uhcp-muted, #5f6875); font-size: .8rem; }
680
680
  .uhcp-subject-identity-card dd { font-weight: 700; margin: .15rem 0 0; overflow-wrap: anywhere; }
681
681
  .uhcp-subject-identity-relationship { align-items: center; background: var(--uhcp-surface-soft, #f6f8fb); border-radius: .8rem; display: grid; gap: .25rem; padding: .8rem; }
682
+ /* Subject-scoped communications remain product-neutral; portals provide brand tokens. */
683
+ .subject-communication-center { display: grid; gap: 1rem; }
684
+ .subject-communication-filters { display: flex; flex-wrap: wrap; gap: .5rem; }
685
+ .subject-communication-filters button { border: 1px solid currentColor; border-radius: 999px; padding: .55rem .9rem; background: transparent; font: inherit; cursor: pointer; }
686
+ .subject-communication-filters button[aria-pressed="true"] { background: currentColor; color: Canvas; }
687
+ .subject-communication-list { display: grid; gap: .75rem; margin: 0; padding: 0; list-style: none; }
688
+ .subject-communication-list > li { display: flex; justify-content: space-between; gap: 1rem; align-items: start; border: 1px solid color-mix(in srgb, currentColor 18%, transparent); border-radius: 1rem; padding: 1rem; }
689
+ .subject-communication-list p { margin: .35rem 0 0; }
690
+ .subject-communication-meta { display: grid; justify-items: end; gap: .35rem; font-size: .875em; }
691
+ .subject-communication-empty { margin: 0; opacity: .72; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uhc-portal-components-react",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "description": "Brand-neutral React portal shell, account preferences and protected-profile UI for UHC and VetChain portals.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",