uhc-portal-components-react 0.1.38 → 0.1.40

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.40
6
+
7
+ - Present subject Communications as an accessible bidirectional channel with
8
+ incoming/outgoing bubbles, sender avatars and an optional text/Bundle
9
+ composer, while preserving the existing message, call and emergency filters.
10
+
11
+ ## 0.1.39
12
+
13
+ - Keep clinical field labels unique to their inputs when speech controls are
14
+ rendered. Microphone buttons now expose only their action as the accessible
15
+ name while retaining the target field in the hover title.
16
+
5
17
  ## 0.1.38
6
18
 
7
19
  - Add a brand-neutral subject communication center that merges messages,
@@ -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
  }
@@ -11,6 +11,17 @@ export type SubjectCommunicationItem = Readonly<{
11
11
  timestamp?: string;
12
12
  status?: string;
13
13
  action?: ReactNode;
14
+ direction?: 'incoming' | 'outgoing' | 'system';
15
+ senderLabel?: string;
16
+ avatarUrl?: string;
17
+ }>;
18
+ export type SubjectCommunicationComposer = Readonly<{
19
+ placeholder: string;
20
+ sendLabel: string;
21
+ attachLabel?: string;
22
+ disabled?: boolean;
23
+ onSend(text: string): void | Promise<void>;
24
+ onAttach?(): void | Promise<void>;
14
25
  }>;
15
26
  export type SubjectCommunicationCenterCopy = Readonly<{
16
27
  heading(subjectLabel: string): string;
@@ -18,9 +29,10 @@ export type SubjectCommunicationCenterCopy = Readonly<{
18
29
  empty: string;
19
30
  }>;
20
31
  /** Brand-neutral, subject-scoped message and internet-call timeline for personal portals. */
21
- export declare function SubjectCommunicationCenter({ subjectLabel, items, copy }: Readonly<{
32
+ export declare function SubjectCommunicationCenter({ subjectLabel, items, copy, composer }: Readonly<{
22
33
  subjectLabel: string;
23
34
  items: readonly SubjectCommunicationItem[];
24
35
  copy?: SubjectCommunicationCenterCopy;
36
+ composer?: SubjectCommunicationComposer;
25
37
  }>): import("react").JSX.Element;
26
38
  //# sourceMappingURL=SubjectCommunicationCenter.d.ts.map
@@ -1 +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"}
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;IAClB,SAAS,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,QAAQ,CAAA;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAC,CAAA;AAEF,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IAClD,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C,QAAQ,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClC,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,QAAQ,EAAE,EAAE,QAAQ,CAAC;IAC1G,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,SAAS,wBAAwB,EAAE,CAAA;IAC1C,IAAI,CAAC,EAAE,8BAA8B,CAAA;IACrC,QAAQ,CAAC,EAAE,4BAA4B,CAAA;CACxC,CAAC,+BAgDD"}
@@ -7,10 +7,18 @@ const DEFAULT_COPY = {
7
7
  };
8
8
  const FILTERS = ['all', 'messages', 'calls', 'emergency'];
9
9
  /** Brand-neutral, subject-scoped message and internet-call timeline for personal portals. */
10
- export function SubjectCommunicationCenter({ subjectLabel, items, copy = DEFAULT_COPY }) {
10
+ export function SubjectCommunicationCenter({ subjectLabel, items, copy = DEFAULT_COPY, composer }) {
11
11
  const [filter, setFilter] = useState('all');
12
+ const [draft, setDraft] = useState('');
12
13
  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
+ 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", role: "log", children: visibleItems.map(item => _jsxs("li", { "data-kind": item.kind, "data-category": item.category, "data-direction": item.direction || 'system', children: [item.avatarUrl ? _jsx("img", { className: "subject-communication-avatar", src: item.avatarUrl, alt: item.senderLabel || item.title }) : null, _jsxs("div", { className: "subject-communication-bubble", children: [item.senderLabel ? _jsx("span", { className: "subject-communication-sender", children: item.senderLabel }) : null, _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)) }), composer ? _jsxs("form", { className: "subject-communication-composer", onSubmit: event => {
15
+ event.preventDefault();
16
+ const text = draft.trim();
17
+ if (!text || composer.disabled)
18
+ return;
19
+ void composer.onSend(text);
20
+ setDraft('');
21
+ }, children: [_jsx("label", { className: "subject-communication-composer-label", htmlFor: "subject-communication-composer-input", children: composer.placeholder }), _jsx("textarea", { id: "subject-communication-composer-input", "aria-label": composer.placeholder, placeholder: composer.placeholder, value: draft, disabled: composer.disabled, onChange: event => setDraft(event.target.value) }), _jsxs("div", { className: "subject-communication-composer-actions", children: [composer.onAttach && composer.attachLabel ? _jsx("button", { type: "button", disabled: composer.disabled, onClick: () => void composer.onAttach?.(), children: composer.attachLabel }) : null, _jsx("button", { type: "submit", disabled: composer.disabled || !draft.trim(), children: composer.sendLabel })] })] }) : null] });
14
22
  }
15
23
  function matchesFilter(item, filter) {
16
24
  if (filter === 'all')
package/dist/styles.css CHANGED
@@ -685,7 +685,19 @@ html[data-theme='dark'] .uhcp-brand-artwork-dark { display: block !important; }
685
685
  .subject-communication-filters button { border: 1px solid currentColor; border-radius: 999px; padding: .55rem .9rem; background: transparent; font: inherit; cursor: pointer; }
686
686
  .subject-communication-filters button[aria-pressed="true"] { background: currentColor; color: Canvas; }
687
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; }
688
+ .subject-communication-list > li { display: flex; justify-content: flex-start; gap: .75rem; align-items: end; }
689
+ .subject-communication-list > li[data-direction="outgoing"] { flex-direction: row-reverse; }
690
+ .subject-communication-list > li[data-direction="system"] { justify-content: center; }
691
+ .subject-communication-avatar { width: 2.5rem; height: 2.5rem; border-radius: 999px; object-fit: cover; flex: 0 0 auto; }
692
+ .subject-communication-bubble { max-width: min(78%, 42rem); border: 1px solid color-mix(in srgb, currentColor 18%, transparent); border-radius: 1rem 1rem 1rem .25rem; padding: .8rem 1rem; background: color-mix(in srgb, Canvas 94%, currentColor 6%); }
693
+ .subject-communication-list > li[data-direction="outgoing"] .subject-communication-bubble { border-radius: 1rem 1rem .25rem 1rem; background: color-mix(in srgb, #66c8d1 18%, Canvas); }
694
+ .subject-communication-sender { display: block; margin-bottom: .2rem; font-size: .8em; font-weight: 700; opacity: .72; }
689
695
  .subject-communication-list p { margin: .35rem 0 0; }
690
696
  .subject-communication-meta { display: grid; justify-items: end; gap: .35rem; font-size: .875em; }
691
697
  .subject-communication-empty { margin: 0; opacity: .72; }
698
+ .subject-communication-composer { display: grid; gap: .65rem; border-top: 1px solid color-mix(in srgb, currentColor 18%, transparent); padding-top: 1rem; }
699
+ .subject-communication-composer-label { font-weight: 700; }
700
+ .subject-communication-composer textarea { min-height: 5rem; resize: vertical; border: 1px solid color-mix(in srgb, currentColor 25%, transparent); border-radius: 1rem; padding: .8rem 1rem; font: inherit; color: inherit; background: Canvas; }
701
+ .subject-communication-composer-actions { display: flex; justify-content: flex-end; gap: .65rem; }
702
+ .subject-communication-composer-actions button { border: 1px solid currentColor; border-radius: 999px; padding: .55rem .9rem; background: transparent; color: inherit; font: inherit; cursor: pointer; }
703
+ .subject-communication-composer-actions button[type="submit"] { background: currentColor; color: Canvas; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uhc-portal-components-react",
3
- "version": "0.1.38",
3
+ "version": "0.1.40",
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",