@medalsocial/meda 3.3.0 → 3.5.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 +35 -1
- package/dist/booking/add-child-sheet.d.ts +2 -1
- package/dist/booking/add-child-sheet.js +2 -1
- package/dist/booking/booking-skeleton.d.ts +2 -1
- package/dist/booking/confirmation.d.ts +2 -1
- package/dist/booking/confirmation.js +7 -6
- package/dist/booking/details-screen.d.ts +5 -1
- package/dist/booking/details-screen.js +13 -8
- package/dist/booking/index.d.ts +2 -2
- package/dist/booking/index.js +2 -2
- package/dist/booking/internal/label-parts.d.ts +36 -21
- package/dist/booking/internal/label-parts.js +71 -43
- package/dist/booking/internal/service-multi.d.ts +55 -0
- package/dist/booking/internal/service-multi.js +83 -0
- package/dist/booking/internal/visit.d.ts +13 -0
- package/dist/booking/internal/visit.js +10 -0
- package/dist/booking/label-keys.d.ts +13 -5
- package/dist/booking/label-keys.js +2 -1
- package/dist/booking/labels.d.ts +37 -8
- package/dist/booking/labels.js +45 -8
- package/dist/booking/login-panel.d.ts +3 -2
- package/dist/booking/login-panel.js +3 -2
- package/dist/booking/login-sheet.d.ts +2 -1
- package/dist/booking/login-sheet.js +2 -1
- package/dist/booking/manage-screen.d.ts +2 -1
- package/dist/booking/manage-screen.js +16 -11
- package/dist/booking/otp-slots.d.ts +2 -1
- package/dist/booking/otp-slots.js +2 -1
- package/dist/booking/portal/age-confirm-card.d.ts +2 -1
- package/dist/booking/portal/child-cards.d.ts +2 -1
- package/dist/booking/portal/data-controls.d.ts +2 -1
- package/dist/booking/portal/data-controls.js +3 -3
- package/dist/booking/portal/family-editor.d.ts +2 -1
- package/dist/booking/portal/family-editor.js +9 -9
- package/dist/booking/portal/logout-button.d.ts +2 -1
- package/dist/booking/portal/logout-button.js +2 -1
- package/dist/booking/portal/portal-shell.d.ts +2 -1
- package/dist/booking/portal/portal-shell.js +3 -2
- package/dist/booking/portal/portal-unreachable.d.ts +2 -1
- package/dist/booking/portal/profile-form.d.ts +2 -1
- package/dist/booking/portal/profile-form.js +3 -2
- package/dist/booking/portal/rebook-cards.d.ts +2 -1
- package/dist/booking/portal/rebook-cards.js +3 -2
- package/dist/booking/portal/upcoming-bookings.d.ts +2 -1
- package/dist/booking/portal/upcoming-bookings.js +3 -3
- package/dist/booking/portal/vipps-link-row.d.ts +2 -1
- package/dist/booking/portal/vipps-link-row.js +7 -6
- package/dist/booking/portal/visit-history.d.ts +2 -1
- package/dist/booking/service-screen.d.ts +78 -3
- package/dist/booking/service-screen.js +131 -46
- package/dist/booking/stylist-screen.d.ts +2 -1
- package/dist/booking/stylist-screen.js +7 -6
- package/dist/booking/summary-bar.d.ts +2 -1
- package/dist/booking/time-screen.d.ts +2 -1
- package/dist/booking/time-screen.js +42 -19
- package/dist/booking/types.d.ts +14 -1
- package/dist/booking/vipps-button.d.ts +2 -1
- package/dist/booking/vipps-button.js +2 -1
- package/dist/booking/who-screen.d.ts +2 -1
- package/dist/booking/who-screen.js +4 -3
- package/package.json +1 -1
- package/skills/components/SKILL.md +4 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ComponentType, type ReactNode } from 'react';
|
|
2
2
|
import { type AddChildSheetLabels } from './add-child-sheet.js';
|
|
3
3
|
import type { BookingFormat } from './format.js';
|
|
4
|
+
import { type BookingLabel } from './labels.js';
|
|
4
5
|
import { type SlotClassNames } from './slots.js';
|
|
5
6
|
import type { NewChild, SaveResult, WizardPerson } from './types.js';
|
|
6
7
|
/**
|
|
@@ -35,7 +36,7 @@ import type { NewChild, SaveResult, WizardPerson } from './types.js';
|
|
|
35
36
|
* from the sheet, grows the list by whole rows and moves nothing sideways.
|
|
36
37
|
*/
|
|
37
38
|
export declare const WHO_SCREEN_LABEL_KEYS: readonly ["who.heading", "who.guest.groupLabel", "who.guest.children.one", "who.guest.children.other", "who.guest.adult", "who.guest.addedList", "who.family.legend", "who.family.self", "who.family.limit", "addChild.trigger", "addChild.title", "addChild.description.saved", "addChild.description.local", "addChild.name", "addChild.birthYear", "addChild.birthYearPlaceholder", "addChild.birthMonth", "addChild.birthMonthUnknown", "addChild.notes", "addChild.missing", "addChild.submit", "addChild.close"];
|
|
38
|
-
export type WhoScreenLabels = Record<(typeof WHO_SCREEN_LABEL_KEYS)[number],
|
|
39
|
+
export type WhoScreenLabels = Record<(typeof WHO_SCREEN_LABEL_KEYS)[number], BookingLabel> & AddChildSheetLabels;
|
|
39
40
|
/**
|
|
40
41
|
* - `root` — the `<section>`
|
|
41
42
|
* - `heading` — the `<h2>`
|
|
@@ -5,6 +5,7 @@ import { useRef } from 'react';
|
|
|
5
5
|
import { cn } from '../lib/utils.js';
|
|
6
6
|
import { ADD_CHILD_SHEET_LABEL_KEYS, AddChildSheet, } from './add-child-sheet.js';
|
|
7
7
|
import { renderLabel } from './internal/label-parts.js';
|
|
8
|
+
import { labelText } from './labels.js';
|
|
8
9
|
import { slotClass } from './slots.js';
|
|
9
10
|
/**
|
|
10
11
|
* The first step — who is the visit for?
|
|
@@ -85,7 +86,7 @@ export function WhoScreen({ labels, format, people, family, guestChoices, addedC
|
|
|
85
86
|
selectedClassName: classNames?.cardSelected,
|
|
86
87
|
};
|
|
87
88
|
if (family === null) {
|
|
88
|
-
return (_jsxs("section", { "aria-labelledby": HEADING_ID, className: slotClass(classNames, 'root', 'space-y-6'), children: [heading, loginRow, _jsxs("div", { className: "space-y-4", children: [_jsx(GuestChips, { choices: guestChoices, people: people, labels: labels, classNames: classNames, onChoose: onChoose }), addedChildren.length > 0 && (_jsx("ul", { "aria-label": labels['who.guest.addedList'], className: "space-y-2", children: addedChildren.map((entry, index) => (_jsx("li", { children: _jsx(PersonCard, { name: entry.person.name ?? '', line: entry.line, index: index, selected: true, disabled: false, onToggle: () => onChoose(people.filter((other) => other.key !== entry.person.key), false), ...cardClasses }) }, entry.person.key))) })), sheet(addedChildren.length >= maxPeople, false)] })] }));
|
|
89
|
+
return (_jsxs("section", { "aria-labelledby": HEADING_ID, className: slotClass(classNames, 'root', 'space-y-6'), children: [heading, loginRow, _jsxs("div", { className: "space-y-4", children: [_jsx(GuestChips, { choices: guestChoices, people: people, labels: labels, classNames: classNames, onChoose: onChoose }), addedChildren.length > 0 && (_jsx("ul", { "aria-label": labelText(labels['who.guest.addedList']), className: "space-y-2", children: addedChildren.map((entry, index) => (_jsx("li", { children: _jsx(PersonCard, { name: entry.person.name ?? '', line: entry.line, index: index, selected: true, disabled: false, onToggle: () => onChoose(people.filter((other) => other.key !== entry.person.key), false), ...cardClasses }) }, entry.person.key))) })), sheet(addedChildren.length >= maxPeople, false)] })] }));
|
|
89
90
|
}
|
|
90
91
|
// Defensively only what this picker draws: the caller clears guest seats
|
|
91
92
|
// when the family appears, and a seat nobody can see must never count
|
|
@@ -134,7 +135,7 @@ function GuestChips({ choices, people, labels, classNames, onChoose, }) {
|
|
|
134
135
|
event.preventDefault();
|
|
135
136
|
refs.current[target]?.focus();
|
|
136
137
|
}
|
|
137
|
-
return (_jsx("div", { role: "radiogroup", "aria-label": labels['who.guest.groupLabel'], className: "grid grid-cols-2 gap-2 sm:grid-cols-4", children: choices.map((choice, index) => {
|
|
138
|
+
return (_jsx("div", { role: "radiogroup", "aria-label": labelText(labels['who.guest.groupLabel']), className: "grid grid-cols-2 gap-2 sm:grid-cols-4", children: choices.map((choice, index) => {
|
|
138
139
|
const pressed = index === checked;
|
|
139
140
|
return (_jsx("button", { ref: (element) => {
|
|
140
141
|
refs.current[index] = element;
|
|
@@ -144,7 +145,7 @@ function GuestChips({ choices, people, labels, classNames, onChoose, }) {
|
|
|
144
145
|
}) }));
|
|
145
146
|
}
|
|
146
147
|
function CheckCircle({ checked }) {
|
|
147
|
-
return (_jsx("span", { "aria-hidden": "true", className: cn('flex size-6 shrink-0 items-center justify-center rounded-full border', checked ? 'border-primary bg-primary text-primary-foreground' : 'border-
|
|
148
|
+
return (_jsx("span", { "aria-hidden": "true", className: cn('flex size-6 shrink-0 items-center justify-center rounded-full border', checked ? 'border-primary bg-primary text-primary-foreground' : 'border-muted-foreground'), children: checked && _jsx(Check, { className: "size-4" }) }));
|
|
148
149
|
}
|
|
149
150
|
/** The default person card: an initial on a tinted avatar, the name, a line, a tick. */
|
|
150
151
|
export function DefaultPersonCard({ name, line, index, selected, disabled, describedBy, onToggle, className, selectedClassName, }) {
|
package/package.json
CHANGED
|
@@ -156,6 +156,10 @@ same wizard / manage page / portal. Rules when editing or adding one:
|
|
|
156
156
|
- **No copy, no clock.** Every string is a `labels` key (`'<screen>.<thing>'`, declared in
|
|
157
157
|
the screen's `*_LABEL_KEYS` array and rolled up in `label-keys.ts`); every date / price
|
|
158
158
|
goes through the `format: BookingFormat` prop — never `Date` getters or `Intl`.
|
|
159
|
+
- **Labels render in the pack's own pieces.** A label is `string | readonly string[]`:
|
|
160
|
+
render it as children through `renderLabel` (string → one text node, array → one per
|
|
161
|
+
element) and as text (`aria-label`, messages) through `fillLabel` / `labelText`. Never
|
|
162
|
+
split a string label at its `{placeholders}`; test both forms (`childNodes`).
|
|
159
163
|
- **Colours through the bridge only** (`bg-primary`, `text-muted-foreground`, …).
|
|
160
164
|
`pnpm lint:tokens` rejects palette colours (`bg-white`, `text-green-600`) and arbitrary
|
|
161
165
|
colour values in `src/booking`.
|