@stamprally/ui 0.7.0 → 0.8.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/dist/index.cjs CHANGED
@@ -7,19 +7,117 @@ var jsxRuntime = require('react/jsx-runtime');
7
7
  // src/index.tsx
8
8
  function RallyViewer({
9
9
  config,
10
+ adapter,
11
+ client,
10
12
  locale,
11
13
  onSpotSelect
12
14
  }) {
13
15
  const activeLocale = locale ?? "en";
16
+ const resolvedConfig = adapter?.config ?? config ?? client?.getConfig();
17
+ const renderConfig = resolvedConfig ?? {
18
+ id: "empty",
19
+ title: "",
20
+ spots: [],
21
+ rewards: []
22
+ };
23
+ const emptyState = {
24
+ rallyId: renderConfig.id,
25
+ records: [],
26
+ updatedAt: (/* @__PURE__ */ new Date(0)).toISOString()
27
+ };
28
+ const resolvedState = adapter?.state ?? client?.getState() ?? emptyState;
29
+ const [selectedSpotId, setSelectedSpotId] = react.useState(null);
30
+ const [proof, setProof] = react.useState("");
31
+ const [feedback, setFeedback] = react.useState(null);
32
+ const [, setClientRevision] = react.useState(0);
33
+ react.useEffect(() => {
34
+ if (client === void 0) return;
35
+ return client.subscribe(() => setClientRevision((revision) => revision + 1));
36
+ }, [client]);
37
+ const selectedSpot = renderConfig.spots.find((spot) => spot.id === selectedSpotId);
38
+ const checkIn = adapter?.onCheckIn ?? (client === void 0 ? void 0 : (spotId, value) => client.checkIn(spotId, value));
39
+ const claimReward = adapter?.onClaimReward ?? (client === void 0 ? void 0 : (rewardId, options) => client.claimReward(rewardId, options));
40
+ const claimed = new Set(resolvedState.records.map((record) => record.stampId));
41
+ const submit = async () => {
42
+ if (selectedSpot === void 0 || checkIn === void 0) return;
43
+ const result = await checkIn(selectedSpot.id, proof);
44
+ setFeedback(result.ok ? "Check-in completed." : result.error.code);
45
+ if (result.ok) {
46
+ setProof("");
47
+ setSelectedSpotId(null);
48
+ }
49
+ };
50
+ if (resolvedConfig === void 0) return null;
14
51
  return /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": "Stamp rally viewer", className: "stamprally-viewer", children: [
15
52
  /* @__PURE__ */ jsxRuntime.jsxs("header", { children: [
16
- /* @__PURE__ */ jsxRuntime.jsx("h1", { children: core.resolveLocalizedText(config.title, activeLocale) }),
17
- config.description !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { children: core.resolveLocalizedText(config.description, activeLocale) })
53
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { children: core.resolveLocalizedText(renderConfig.title, activeLocale) }),
54
+ renderConfig.description !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { children: core.resolveLocalizedText(renderConfig.description, activeLocale) }),
55
+ adapter?.onSync !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => void adapter.onSync?.(), children: "Sync" })
18
56
  ] }),
19
- /* @__PURE__ */ jsxRuntime.jsx("ol", { children: config.spots.map((spot) => /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
20
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => onSpotSelect?.(spot.id), children: core.resolveLocalizedText(spot.name, activeLocale) }),
57
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "grid", "aria-label": "Stamp rally spots", children: renderConfig.spots.map((spot, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
58
+ /* @__PURE__ */ jsxRuntime.jsxs(
59
+ "button",
60
+ {
61
+ type: "button",
62
+ "aria-label": `${core.resolveLocalizedText(spot.name, activeLocale)}${claimed.has(spot.id) ? ", claimed" : ", available"}`,
63
+ onClick: () => {
64
+ onSpotSelect?.(spot.id);
65
+ setSelectedSpotId(spot.id);
66
+ setFeedback(null);
67
+ },
68
+ children: [
69
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { "aria-hidden": "true", children: [
70
+ "#",
71
+ String(index + 1).padStart(2, "0")
72
+ ] }),
73
+ " ",
74
+ core.resolveLocalizedText(spot.name, activeLocale)
75
+ ]
76
+ }
77
+ ),
21
78
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: spot.conditions[0]?.type ?? "custom" })
22
- ] }, spot.id)) })
79
+ ] }, spot.id)) }),
80
+ /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", "aria-live": "polite", children: feedback ?? `${claimed.size} / ${renderConfig.spots.length} claimed` }),
81
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { "aria-label": "Rewards", children: [
82
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Rewards" }),
83
+ renderConfig.rewards.map((reward) => {
84
+ const rewardState = resolvedState.rewards?.find((item) => item.rewardId === reward.id);
85
+ const available = rewardState?.status === "AVAILABLE";
86
+ return /* @__PURE__ */ jsxRuntime.jsxs("article", { children: [
87
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { children: core.resolveLocalizedText(reward.title, activeLocale) }),
88
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: rewardState?.status ?? "LOCKED" }),
89
+ claimReward !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
90
+ "button",
91
+ {
92
+ type: "button",
93
+ disabled: !available,
94
+ onClick: () => void claimReward(reward.id).then((result) => {
95
+ setFeedback(result.ok ? "Reward claimed." : result.error.code);
96
+ }),
97
+ children: "Claim reward"
98
+ }
99
+ )
100
+ ] }, reward.id);
101
+ })
102
+ ] }),
103
+ selectedSpot !== void 0 && checkIn !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "dialog", "aria-modal": "true", "aria-labelledby": "rally-viewer-spot-title", children: [
104
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { id: "rally-viewer-spot-title", children: core.resolveLocalizedText(selectedSpot.name, activeLocale) }),
105
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: core.resolveLocalizedText(selectedSpot.description, activeLocale) }),
106
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
107
+ "Proof",
108
+ /* @__PURE__ */ jsxRuntime.jsx("input", { value: proof, onChange: (event) => setProof(event.target.value) })
109
+ ] }),
110
+ /* @__PURE__ */ jsxRuntime.jsx(
111
+ "button",
112
+ {
113
+ type: "button",
114
+ onClick: () => void submit(),
115
+ disabled: claimed.has(selectedSpot.id),
116
+ children: "Check in"
117
+ }
118
+ ),
119
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => setSelectedSpotId(null), children: "Close" })
120
+ ] })
23
121
  ] });
24
122
  }
25
123
  function useFocusTrap(active, onClose, closeDisabled = false) {
@@ -146,8 +244,29 @@ function StampSheet({
146
244
  locale = "ja",
147
245
  dictionary,
148
246
  theme = config.theme ?? core.DEFAULT_SHEET_THEME,
149
- onStampSelect
247
+ onStampSelect,
248
+ adapter
150
249
  }) {
250
+ if ("spots" in config) {
251
+ if (adapter === void 0)
252
+ return /* @__PURE__ */ jsxRuntime.jsx(
253
+ RallyViewer,
254
+ {
255
+ config,
256
+ locale,
257
+ ...onStampSelect === void 0 ? {} : { onSpotSelect: onStampSelect }
258
+ }
259
+ );
260
+ return /* @__PURE__ */ jsxRuntime.jsx(
261
+ RallyViewer,
262
+ {
263
+ config,
264
+ adapter,
265
+ locale,
266
+ ...onStampSelect === void 0 ? {} : { onSpotSelect: onStampSelect }
267
+ }
268
+ );
269
+ }
151
270
  const acquired = new Set(state?.records.map((record) => record.stampId) ?? []);
152
271
  const next = new Set(progress?.nextAvailableStamps.map((stamp) => stamp.id) ?? []);
153
272
  const count = progress?.acquired ?? acquired.size;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx"],"names":["jsxs","jsx","resolveLocalizedText","useRef","useEffect","DEFAULT_SHEET_THEME","useState"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n type ConsumeResult,\n DEFAULT_SHEET_THEME,\n type LocaleDictionary,\n type LocalizedText,\n type PublicRallyConfig,\n type RallyConfig,\n type RewardItem,\n type RewardState,\n resolveLocalizedText,\n type SheetTheme,\n type SlotShape,\n type SpotItem,\n type StampRallyProgress,\n type StampRallyState,\n type SupportedLocale,\n type VerificationContext,\n} from \"@stamprally/core\";\nimport type { CSSProperties, FormEvent, RefObject } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport type { LocaleDictionary } from \"@stamprally/core\";\n\nexport interface RallyViewerProps<TLocale extends string = string> {\n readonly config: PublicRallyConfig<TLocale>;\n readonly locale?: TLocale;\n readonly onSpotSelect?: (spotId: string) => void;\n}\n\n/** Lightweight public-config viewer for applications that do not need the legacy StampSheet state model. */\nexport function RallyViewer<TLocale extends string = string>({\n config,\n locale,\n onSpotSelect,\n}: RallyViewerProps<TLocale>) {\n const activeLocale = locale ?? (\"en\" as TLocale);\n return (\n <section aria-label=\"Stamp rally viewer\" className=\"stamprally-viewer\">\n <header>\n <h1>{resolveLocalizedText(config.title, activeLocale)}</h1>\n {config.description !== undefined && (\n <p>{resolveLocalizedText(config.description, activeLocale)}</p>\n )}\n </header>\n <ol>\n {config.spots.map((spot) => (\n <li key={spot.id}>\n <button type=\"button\" onClick={() => onSpotSelect?.(spot.id)}>\n {resolveLocalizedText(spot.name, activeLocale)}\n </button>\n <span>{spot.conditions[0]?.type ?? \"custom\"}</span>\n </li>\n ))}\n </ol>\n </section>\n );\n}\n\nfunction useFocusTrap(\n active: boolean,\n onClose: (() => void) | undefined,\n closeDisabled = false,\n): RefObject<HTMLDivElement | null> {\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n if (!active) return;\n const container = containerRef.current;\n if (container === null) return;\n\n const focusableSelector =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n const focusable = (): ReadonlyArray<HTMLElement> =>\n Array.from(container.querySelectorAll<HTMLElement>(focusableSelector));\n const first = focusable()[0];\n first?.focus();\n\n const handleKeyDown = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n if (!closeDisabled) {\n event.preventDefault();\n onClose?.();\n }\n return;\n }\n if (event.key !== \"Tab\") return;\n\n const elements = focusable();\n if (elements.length === 0) {\n event.preventDefault();\n container.focus();\n return;\n }\n const firstElement = elements[0];\n const lastElement = elements[elements.length - 1];\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement?.focus();\n } else if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault();\n firstElement?.focus();\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [active, closeDisabled, onClose]);\n\n return containerRef;\n}\n\nexport interface StampPresentation {\n readonly label?: string;\n readonly icon?: string;\n readonly ink?: \"vermilion\" | \"indigo\";\n readonly channel?: \"instant\" | \"qr\" | \"nfc\" | \"geo\";\n}\n\nexport interface StampSlotProps<TLocale extends string = SupportedLocale> {\n readonly stamp: SpotItem<TLocale>;\n readonly record?: StampRallyState[\"records\"][number] | undefined;\n readonly isNext?: boolean;\n readonly slotNumber?: number;\n readonly presentation?: StampPresentation | undefined;\n readonly isAnimating?: boolean;\n readonly disabled?: boolean;\n readonly slotShape?: SlotShape;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly statusText?: string;\n readonly onSelect?: () => void;\n}\n\nconst FONT_STACKS: Readonly<Record<NonNullable<SheetTheme[\"fontFamily\"]>, string>> = {\n \"system-ui\": 'system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif',\n serif: 'Georgia, \"Times New Roman\", \"Yu Mincho\", serif',\n \"rounded-sans\": '\"Arial Rounded MT Bold\", \"Hiragino Maru Gothic ProN\", \"Yu Gothic\", sans-serif',\n monospace: 'ui-monospace, SFMono-Regular, Consolas, \"Liberation Mono\", monospace',\n handwritten: '\"Segoe Print\", \"Bradley Hand\", \"Comic Sans MS\", cursive',\n};\n\nfunction formatStampDate(value: string): string {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value;\n const pad = (part: number) => String(part).padStart(2, \"0\");\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;\n}\n\nexport function StampSlot<TLocale extends string = SupportedLocale>({\n stamp,\n record,\n isNext = false,\n slotNumber = 1,\n presentation = {},\n isAnimating = false,\n disabled = false,\n slotShape = \"rounded\",\n locale = \"ja\" as TLocale,\n statusText,\n onSelect,\n}: StampSlotProps<TLocale>) {\n const status = record === undefined ? (isNext ? \"available\" : \"locked\") : \"stamped\";\n const resolvedStatus = statusText ?? status;\n const statusSeparator = statusText !== undefined && locale === \"ja\" ? \"、\" : \", \";\n const name = resolveLocalizedText(stamp.name, locale);\n const label = presentation.label ?? stamp.condition.type;\n return (\n <button\n type=\"button\"\n disabled={disabled}\n onClick={onSelect}\n aria-label={`#${String(slotNumber).padStart(2, \"0\")} ${name}${statusSeparator}${resolvedStatus}`}\n aria-disabled={disabled}\n data-status={status}\n data-shape={slotShape}\n className={`stamp-slot stamp-slot--${status} stamp-slot--${presentation.ink ?? \"vermilion\"} stamp-slot--shape-${slotShape}${isAnimating ? \" stamp-slot--animating\" : \"\"}`}\n style={{ \"--stamp-primary\": \"var(--stamprally-primary, #9e551e)\" } as CSSProperties}\n >\n <span className=\"stamp-slot__topline\">\n <span className=\"stamp-slot__number\">#{String(slotNumber).padStart(2, \"0\")}</span>\n <span className={`stamp-slot__state stamp-slot__state--${status}`}>{resolvedStatus}</span>\n </span>\n <span className=\"stamp-slot__watermark\" aria-hidden=\"true\">\n {presentation.icon ?? \"✦\"}\n </span>\n <span className=\"stamp-slot__name\">{name}</span>\n <span className=\"stamp-slot__condition\">\n <span aria-hidden=\"true\">{presentation.icon ?? \"✦\"}</span>\n {label}\n </span>\n {record !== undefined && (\n <span\n className={`stamp-imprint ${isAnimating ? \"stamp-press\" : \"\"}`}\n role=\"img\"\n aria-label={`Acquired at ${formatStampDate(record.acquiredAt)}`}\n >\n <span className=\"stamp-imprint__inner\">\n <span className=\"stamp-imprint__word\">STAMP</span>\n <span className=\"stamp-imprint__date\">{formatStampDate(record.acquiredAt)}</span>\n </span>\n </span>\n )}\n </button>\n );\n}\n\nexport interface StampSheetProps<TLocale extends string = SupportedLocale> {\n readonly title?: LocalizedText<TLocale>;\n readonly config: RallyConfig<TLocale>;\n readonly state?: StampRallyState | null;\n readonly progress?: StampRallyProgress;\n readonly presentations?: Readonly<Record<string, StampPresentation>>;\n readonly animatedStampId?: string | null;\n readonly disabled?: boolean;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly theme?: SheetTheme;\n readonly onStampSelect?: (stampId: string) => void;\n}\n\nexport function StampSheet<TLocale extends string = SupportedLocale>({\n title,\n config,\n state = null,\n progress,\n presentations = {},\n animatedStampId = null,\n disabled = false,\n locale = \"ja\" as TLocale,\n dictionary,\n theme = config.theme ?? DEFAULT_SHEET_THEME,\n onStampSelect,\n}: StampSheetProps<TLocale>) {\n const acquired = new Set(state?.records.map((record) => record.stampId) ?? []);\n const next = new Set(progress?.nextAvailableStamps.map((stamp) => stamp.id) ?? []);\n const count = progress?.acquired ?? acquired.size;\n const total = progress?.total ?? config.stamps.length;\n const percentage = progress?.percentage ?? (total === 0 ? 0 : (count / total) * 100);\n const style = {\n \"--stamp-primary\": `var(--stamprally-primary-override, ${theme.primaryColor})`,\n \"--stamp-bg\": `var(--stamprally-background-override, ${theme.backgroundColor ?? DEFAULT_SHEET_THEME.backgroundColor ?? \"#ffffff\"})`,\n \"--stamp-card-bg\": `var(--stamprally-card-override, ${theme.cardBackgroundColor})`,\n \"--stamp-text\": `var(--stamprally-text-override, ${theme.textColor})`,\n \"--stamp-grid-cols\": String(theme.gridColumns),\n \"--stamp-grid-cols-mobile\": String(Math.min(theme.gridColumns, 2)),\n \"--stamp-unclaimed-opacity\": String(theme.unclaimedOpacity ?? 1),\n \"--stamp-font-family\": FONT_STACKS[theme.fontFamily ?? \"serif\"],\n ...(theme.completedStampColor === undefined\n ? {}\n : { \"--stamp-completed-color\": theme.completedStampColor }),\n \"--stamprally-primary\": `var(--stamprally-primary-override, ${theme.primaryColor})`,\n \"--stamprally-background\": `var(--stamprally-background-override, ${theme.backgroundColor ?? \"transparent\"})`,\n \"--stamprally-card\": `var(--stamprally-card-override, ${theme.cardBackgroundColor})`,\n \"--stamprally-text\": `var(--stamprally-text-override, ${theme.textColor})`,\n \"--stamprally-columns\": String(theme.gridColumns),\n } as CSSProperties;\n const messages = {\n available: dictionary?.[locale]?.available ?? (locale === \"en\" ? \"available\" : \"取得可能\"),\n locked: dictionary?.[locale]?.locked ?? (locale === \"en\" ? \"locked\" : \"順序待ち\"),\n stamped: dictionary?.[locale]?.stamped ?? (locale === \"en\" ? \"stamped\" : \"取得済み\"),\n remaining: (value: number) =>\n dictionary?.[locale]?.remaining?.replace(\"{count}\", String(value)) ??\n (locale === \"en\" ? `${value} spots remaining` : `あと${value}箇所`),\n completed:\n dictionary?.[locale]?.completed ?? (locale === \"en\" ? \"RALLY COMPLETED\" : \"ラリー達成\"),\n };\n return (\n <section\n className={`stamp-sheet ${percentage >= 100 ? \"stamp-sheet--completed\" : \"\"}`}\n style={style}\n aria-label={resolveLocalizedText(title, locale) || config.id}\n >\n <header className=\"stamp-sheet__header\">\n <h2>{resolveLocalizedText(title, locale) || config.id}</h2>\n <span className=\"stamp-sheet__score\" role=\"status\" aria-live=\"polite\">\n {count} / {total}\n </span>\n </header>\n <div className=\"stamp-sheet__progress-label\">\n <span>{messages.remaining(Math.max(0, total - count))}</span>\n <strong>{Math.round(percentage)}%</strong>\n </div>\n <div\n className=\"stamp-sheet__progress-track\"\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(percentage)}\n aria-label={locale === \"en\" ? \"Rally progress\" : \"スタンプ取得進捗\"}\n >\n <span\n className=\"stamp-sheet__progress-fill\"\n style={{ display: \"block\", width: `${percentage}%` }}\n />\n </div>\n <div className=\"stamp-sheet__grid\">\n {config.stamps.map((stamp, index) => {\n const recordForStamp = state?.records.find((record) => record.stampId === stamp.id);\n return (\n <StampSlot\n key={stamp.id}\n stamp={stamp}\n {...(recordForStamp === undefined ? {} : { record: recordForStamp })}\n isNext={next.has(stamp.id)}\n slotNumber={index + 1}\n {...(presentations[stamp.id] === undefined\n ? {}\n : { presentation: presentations[stamp.id] })}\n isAnimating={animatedStampId === stamp.id}\n disabled={disabled}\n slotShape={theme.slotShape}\n locale={locale}\n {...(dictionary === undefined ? {} : { dictionary })}\n statusText={\n recordForStamp === undefined\n ? next.has(stamp.id)\n ? messages.available\n : messages.locked\n : messages.stamped\n }\n onSelect={() => onStampSelect?.(stamp.id)}\n />\n );\n })}\n </div>\n {percentage >= 100 && (\n <div className=\"stamp-sheet__complete-mark\" role=\"status\" aria-live=\"polite\">\n COMPLETE!!\n </div>\n )}\n {percentage >= 100 && (\n <div className=\"stamp-sheet__complete-message\">{messages.completed}</div>\n )}\n </section>\n );\n}\n\nexport interface AcquisitionFeedback {\n readonly ok: boolean;\n readonly message: string;\n}\nexport interface StampModalProps<TLocale extends string = SupportedLocale> {\n readonly open: boolean;\n readonly stamp: SpotItem<TLocale> | null;\n readonly record?: StampRallyState[\"records\"][number] | undefined;\n readonly presentation?: StampPresentation | null;\n readonly requiredStampName?: string | null;\n readonly isAvailable?: boolean;\n readonly isPending?: boolean;\n readonly isCompleted?: boolean;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly onClose: () => void;\n readonly onAcquire?: (\n stampId: string,\n context: VerificationContext,\n ) => Promise<AcquisitionFeedback>;\n readonly onCheckIn?: (\n stampId: string,\n context: VerificationContext,\n ) => Promise<AcquisitionFeedback>;\n readonly onNotify?: (feedback: AcquisitionFeedback) => void;\n}\n\nexport function StampModal<TLocale extends string = SupportedLocale>({\n open,\n stamp,\n record,\n isAvailable = true,\n isPending = false,\n locale = \"ja\" as TLocale,\n dictionary,\n onClose,\n onAcquire,\n onCheckIn,\n onNotify,\n}: StampModalProps<TLocale>) {\n const [token, setToken] = useState(\"\");\n const modalRef = useFocusTrap(open && stamp !== null, onClose, isPending);\n useEffect(() => {\n if (!open) setToken(\"\");\n }, [open]);\n if (!open || stamp === null) return null;\n const submit = async (context: VerificationContext): Promise<void> => {\n if (!isAvailable || record !== undefined) return;\n const handler = onAcquire ?? onCheckIn;\n if (handler === undefined) return;\n const feedback = await handler(stamp.id, context);\n onNotify?.(feedback);\n if (feedback.ok) onClose();\n };\n const name = resolveLocalizedText(stamp.name, locale);\n const messages = dictionary?.[locale] ?? {};\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"stamprally-modal-title\"\n className=\"stamprally-modal\"\n >\n <div className=\"stamprally-modal__panel\" ref={modalRef} tabIndex={-1}>\n <button\n type=\"button\"\n aria-label=\"Close stamp details\"\n aria-disabled={isPending}\n onClick={onClose}\n disabled={isPending}\n >\n ×\n </button>\n <h2 id=\"stamprally-modal-title\">{name}</h2>\n {record !== undefined ? (\n <p>{messages.alreadyClaimed ?? \"Already claimed.\"}</p>\n ) : (\n <p>{resolveLocalizedText(stamp.description, locale)}</p>\n )}\n {stamp.condition.type === \"token\" ? (\n <form\n onSubmit={(event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void submit({ type: \"token\", token });\n }}\n >\n <label>\n {messages.passcode ?? \"Passcode\"}{\" \"}\n <input value={token} onChange={(event) => setToken(event.target.value)} />\n </label>\n <button\n type=\"submit\"\n aria-label=\"Claim stamp\"\n aria-disabled={!isAvailable || isPending}\n disabled={!isAvailable || isPending}\n >\n {messages.claimStamp ?? \"Claim stamp\"}\n </button>\n </form>\n ) : (\n <button\n type=\"button\"\n aria-label=\"Claim stamp\"\n aria-disabled={!isAvailable || isPending}\n onClick={() => void submit({ type: \"instant\" })}\n disabled={!isAvailable || isPending}\n >\n {messages.claimStamp ?? \"Claim stamp\"}\n </button>\n )}\n </div>\n </div>\n );\n}\n\nexport interface RewardPanelProps<TLocale extends string = SupportedLocale> {\n readonly rewards: ReadonlyArray<RewardItem<TLocale>>;\n readonly states: ReadonlyArray<RewardState>;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly isPending?: boolean;\n readonly open?: boolean;\n readonly onClose?: () => void;\n readonly onRedeem: (\n rewardId: string,\n options?: { readonly passcode?: string; readonly staffId?: string },\n ) => Promise<ConsumeResult>;\n readonly onNotify?: (ok: boolean, message: string) => void;\n}\n\nexport function RewardPanel<TLocale extends string = SupportedLocale>({\n rewards,\n states,\n locale = \"ja\" as TLocale,\n dictionary,\n isPending = false,\n open = true,\n onClose,\n onRedeem,\n onNotify,\n}: RewardPanelProps<TLocale>) {\n const [passcodes, setPasscodes] = useState<Readonly<Record<string, string>>>({});\n const panelRef = useFocusTrap(open && onClose !== undefined, onClose, isPending);\n if (!open) return null;\n return (\n <section\n ref={panelRef}\n role=\"dialog\"\n aria-labelledby=\"stamprally-rewards-title\"\n aria-modal=\"true\"\n className=\"stamprally-rewards\"\n tabIndex={-1}\n >\n <header className=\"stamprally-rewards__header\">\n <h2 id=\"stamprally-rewards-title\">{dictionary?.[locale]?.rewards ?? \"Rewards\"}</h2>\n {onClose !== undefined && (\n <button\n type=\"button\"\n aria-label=\"Close rewards\"\n aria-disabled={isPending}\n disabled={isPending}\n onClick={onClose}\n >\n ×\n </button>\n )}\n </header>\n {rewards.map((reward) => {\n const state = states.find((item) => item.rewardId === reward.id);\n const available = state?.status === \"AVAILABLE\";\n const redeem = async (options?: { readonly passcode?: string }): Promise<void> => {\n const result = await onRedeem(reward.id, options);\n onNotify?.(\n result.ok,\n result.ok\n ? (dictionary?.[locale]?.rewardClaimed ?? \"Reward claimed.\")\n : result.error.code,\n );\n };\n return (\n <article\n key={reward.id}\n className={`stamprally-reward stamprally-reward--${state?.status ?? \"LOCKED\"}`}\n >\n <h3>{resolveLocalizedText(reward.title, locale)}</h3>\n <p>{resolveLocalizedText(reward.description, locale)}</p>\n <span role=\"status\" aria-live=\"polite\">\n {state?.status ?? \"LOCKED\"}\n </span>\n {reward.redemptionMethod === \"staff_passcode\" && (\n <form\n onSubmit={(event) => {\n event.preventDefault();\n void redeem({ passcode: passcodes[reward.id] ?? \"\" });\n }}\n >\n <label>\n {dictionary?.[locale]?.staffPasscode ?? \"Staff passcode\"}{\" \"}\n <input\n type=\"password\"\n value={passcodes[reward.id] ?? \"\"}\n onChange={(event) =>\n setPasscodes((current) => ({ ...current, [reward.id]: event.target.value }))\n }\n />\n </label>\n <button\n type=\"submit\"\n aria-label={`Redeem ${resolveLocalizedText(reward.title, locale)}`}\n aria-disabled={!available || isPending}\n disabled={!available || isPending}\n >\n {dictionary?.[locale]?.redeem ?? \"Redeem\"}\n </button>\n </form>\n )}\n {reward.redemptionMethod !== \"staff_passcode\" && (\n <button\n type=\"button\"\n aria-label={`Redeem ${resolveLocalizedText(reward.title, locale)}`}\n aria-disabled={!available || isPending}\n disabled={!available || isPending}\n onClick={() => void redeem()}\n >\n {dictionary?.[locale]?.redeem ?? \"Redeem\"}\n </button>\n )}\n </article>\n );\n })}\n </section>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/index.tsx"],"names":["useState","useEffect","jsxs","jsx","resolveLocalizedText","useRef","DEFAULT_SHEET_THEME"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n type ClaimOptions,\n type ConsumeResult,\n DEFAULT_SHEET_THEME,\n type LocaleDictionary,\n type LocalizedText,\n type PublicRallyConfig,\n type RallyConfig,\n type RewardItem,\n type RewardState,\n resolveLocalizedText,\n type SheetTheme,\n type SlotShape,\n type SpotItem,\n type StampRallyProgress,\n type StampRallyState,\n type SupportedLocale,\n type UniversalCheckInResult,\n type UniversalClaimResult,\n type UniversalStampRallyClient,\n type UserRallyState,\n type VerificationContext,\n} from \"@stamprally/core\";\nimport type { CSSProperties, FormEvent, RefObject } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport type { LocaleDictionary } from \"@stamprally/core\";\n\nexport interface RallyViewerAdapter<TLocale extends string = string> {\n readonly state: UserRallyState;\n readonly config: PublicRallyConfig<TLocale>;\n readonly onCheckIn: (spotId: string, proof: unknown) => Promise<UniversalCheckInResult>;\n readonly onClaimReward: (\n rewardId: string,\n options?: ClaimOptions,\n ) => Promise<UniversalClaimResult>;\n readonly onSync?: () => Promise<void>;\n}\n\nexport interface RallyViewerProps<TLocale extends string = string> {\n readonly config?: PublicRallyConfig<TLocale>;\n readonly adapter?: RallyViewerAdapter<TLocale>;\n readonly client?: UniversalStampRallyClient;\n readonly locale?: TLocale;\n readonly onSpotSelect?: (spotId: string) => void;\n}\n\n/** Lightweight public-config viewer for applications that do not need the legacy StampSheet state model. */\nexport function RallyViewer<TLocale extends string = string>({\n config,\n adapter,\n client,\n locale,\n onSpotSelect,\n}: RallyViewerProps<TLocale>) {\n const activeLocale = locale ?? (\"en\" as TLocale);\n const resolvedConfig = adapter?.config ?? config ?? client?.getConfig();\n const renderConfig: PublicRallyConfig<TLocale> = resolvedConfig ?? {\n id: \"empty\",\n version: \"0.7.0\",\n title: \"\",\n spots: [],\n rewards: [],\n };\n const emptyState: UserRallyState = {\n rallyId: renderConfig.id,\n records: [],\n updatedAt: new Date(0).toISOString(),\n };\n const resolvedState = adapter?.state ?? client?.getState() ?? emptyState;\n const [selectedSpotId, setSelectedSpotId] = useState<string | null>(null);\n const [proof, setProof] = useState(\"\");\n const [feedback, setFeedback] = useState<string | null>(null);\n const [, setClientRevision] = useState(0);\n useEffect(() => {\n if (client === undefined) return;\n return client.subscribe(() => setClientRevision((revision) => revision + 1));\n }, [client]);\n const selectedSpot = renderConfig.spots.find((spot) => spot.id === selectedSpotId);\n const checkIn =\n adapter?.onCheckIn ??\n (client === undefined\n ? undefined\n : (spotId: string, value: unknown) => client.checkIn(spotId, value));\n const claimReward =\n adapter?.onClaimReward ??\n (client === undefined\n ? undefined\n : (rewardId: string, options?: ClaimOptions) => client.claimReward(rewardId, options));\n const claimed = new Set(resolvedState.records.map((record) => record.stampId));\n const submit = async (): Promise<void> => {\n if (selectedSpot === undefined || checkIn === undefined) return;\n const result = await checkIn(selectedSpot.id, proof);\n setFeedback(result.ok ? \"Check-in completed.\" : result.error.code);\n if (result.ok) {\n setProof(\"\");\n setSelectedSpotId(null);\n }\n };\n if (resolvedConfig === undefined) return null;\n return (\n <section aria-label=\"Stamp rally viewer\" className=\"stamprally-viewer\">\n <header>\n <h1>{resolveLocalizedText(renderConfig.title, activeLocale)}</h1>\n {renderConfig.description !== undefined && (\n <p>{resolveLocalizedText(renderConfig.description, activeLocale)}</p>\n )}\n {adapter?.onSync !== undefined && (\n <button type=\"button\" onClick={() => void adapter.onSync?.()}>\n Sync\n </button>\n )}\n </header>\n {/* biome-ignore lint/a11y/useSemanticElements: The viewer exposes the requested ARIA grid contract. */}\n <div role=\"grid\" aria-label=\"Stamp rally spots\">\n {renderConfig.spots.map((spot, index) => (\n <div key={spot.id}>\n <button\n type=\"button\"\n aria-label={`${resolveLocalizedText(spot.name, activeLocale)}${claimed.has(spot.id) ? \", claimed\" : \", available\"}`}\n onClick={() => {\n onSpotSelect?.(spot.id);\n setSelectedSpotId(spot.id);\n setFeedback(null);\n }}\n >\n <span aria-hidden=\"true\">#{String(index + 1).padStart(2, \"0\")}</span>{\" \"}\n {resolveLocalizedText(spot.name, activeLocale)}\n </button>\n <span>{spot.conditions[0]?.type ?? \"custom\"}</span>\n </div>\n ))}\n </div>\n <p role=\"status\" aria-live=\"polite\">\n {feedback ?? `${claimed.size} / ${renderConfig.spots.length} claimed`}\n </p>\n <section aria-label=\"Rewards\">\n <h2>Rewards</h2>\n {renderConfig.rewards.map((reward) => {\n const rewardState = resolvedState.rewards?.find((item) => item.rewardId === reward.id);\n const available = rewardState?.status === \"AVAILABLE\";\n return (\n <article key={reward.id}>\n <h3>{resolveLocalizedText(reward.title, activeLocale)}</h3>\n <span>{rewardState?.status ?? \"LOCKED\"}</span>\n {claimReward !== undefined && (\n <button\n type=\"button\"\n disabled={!available}\n onClick={() =>\n void claimReward(reward.id).then((result) => {\n setFeedback(result.ok ? \"Reward claimed.\" : result.error.code);\n })\n }\n >\n Claim reward\n </button>\n )}\n </article>\n );\n })}\n </section>\n {selectedSpot !== undefined && checkIn !== undefined && (\n <div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"rally-viewer-spot-title\">\n <h2 id=\"rally-viewer-spot-title\">\n {resolveLocalizedText(selectedSpot.name, activeLocale)}\n </h2>\n <p>{resolveLocalizedText(selectedSpot.description, activeLocale)}</p>\n <label>\n Proof\n <input value={proof} onChange={(event) => setProof(event.target.value)} />\n </label>\n <button\n type=\"button\"\n onClick={() => void submit()}\n disabled={claimed.has(selectedSpot.id)}\n >\n Check in\n </button>\n <button type=\"button\" onClick={() => setSelectedSpotId(null)}>\n Close\n </button>\n </div>\n )}\n </section>\n );\n}\n\nfunction useFocusTrap(\n active: boolean,\n onClose: (() => void) | undefined,\n closeDisabled = false,\n): RefObject<HTMLDivElement | null> {\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n if (!active) return;\n const container = containerRef.current;\n if (container === null) return;\n\n const focusableSelector =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n const focusable = (): ReadonlyArray<HTMLElement> =>\n Array.from(container.querySelectorAll<HTMLElement>(focusableSelector));\n const first = focusable()[0];\n first?.focus();\n\n const handleKeyDown = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n if (!closeDisabled) {\n event.preventDefault();\n onClose?.();\n }\n return;\n }\n if (event.key !== \"Tab\") return;\n\n const elements = focusable();\n if (elements.length === 0) {\n event.preventDefault();\n container.focus();\n return;\n }\n const firstElement = elements[0];\n const lastElement = elements[elements.length - 1];\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement?.focus();\n } else if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault();\n firstElement?.focus();\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [active, closeDisabled, onClose]);\n\n return containerRef;\n}\n\nexport interface StampPresentation {\n readonly label?: string;\n readonly icon?: string;\n readonly ink?: \"vermilion\" | \"indigo\";\n readonly channel?: \"instant\" | \"qr\" | \"nfc\" | \"geo\";\n}\n\nexport interface StampSlotProps<TLocale extends string = SupportedLocale> {\n readonly stamp: SpotItem<TLocale>;\n readonly record?: StampRallyState[\"records\"][number] | undefined;\n readonly isNext?: boolean;\n readonly slotNumber?: number;\n readonly presentation?: StampPresentation | undefined;\n readonly isAnimating?: boolean;\n readonly disabled?: boolean;\n readonly slotShape?: SlotShape;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly statusText?: string;\n readonly onSelect?: () => void;\n}\n\nconst FONT_STACKS: Readonly<Record<NonNullable<SheetTheme[\"fontFamily\"]>, string>> = {\n \"system-ui\": 'system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif',\n serif: 'Georgia, \"Times New Roman\", \"Yu Mincho\", serif',\n \"rounded-sans\": '\"Arial Rounded MT Bold\", \"Hiragino Maru Gothic ProN\", \"Yu Gothic\", sans-serif',\n monospace: 'ui-monospace, SFMono-Regular, Consolas, \"Liberation Mono\", monospace',\n handwritten: '\"Segoe Print\", \"Bradley Hand\", \"Comic Sans MS\", cursive',\n};\n\nfunction formatStampDate(value: string): string {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value;\n const pad = (part: number) => String(part).padStart(2, \"0\");\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;\n}\n\nexport function StampSlot<TLocale extends string = SupportedLocale>({\n stamp,\n record,\n isNext = false,\n slotNumber = 1,\n presentation = {},\n isAnimating = false,\n disabled = false,\n slotShape = \"rounded\",\n locale = \"ja\" as TLocale,\n statusText,\n onSelect,\n}: StampSlotProps<TLocale>) {\n const status = record === undefined ? (isNext ? \"available\" : \"locked\") : \"stamped\";\n const resolvedStatus = statusText ?? status;\n const statusSeparator = statusText !== undefined && locale === \"ja\" ? \"、\" : \", \";\n const name = resolveLocalizedText(stamp.name, locale);\n const label = presentation.label ?? stamp.condition.type;\n return (\n <button\n type=\"button\"\n disabled={disabled}\n onClick={onSelect}\n aria-label={`#${String(slotNumber).padStart(2, \"0\")} ${name}${statusSeparator}${resolvedStatus}`}\n aria-disabled={disabled}\n data-status={status}\n data-shape={slotShape}\n className={`stamp-slot stamp-slot--${status} stamp-slot--${presentation.ink ?? \"vermilion\"} stamp-slot--shape-${slotShape}${isAnimating ? \" stamp-slot--animating\" : \"\"}`}\n style={{ \"--stamp-primary\": \"var(--stamprally-primary, #9e551e)\" } as CSSProperties}\n >\n <span className=\"stamp-slot__topline\">\n <span className=\"stamp-slot__number\">#{String(slotNumber).padStart(2, \"0\")}</span>\n <span className={`stamp-slot__state stamp-slot__state--${status}`}>{resolvedStatus}</span>\n </span>\n <span className=\"stamp-slot__watermark\" aria-hidden=\"true\">\n {presentation.icon ?? \"✦\"}\n </span>\n <span className=\"stamp-slot__name\">{name}</span>\n <span className=\"stamp-slot__condition\">\n <span aria-hidden=\"true\">{presentation.icon ?? \"✦\"}</span>\n {label}\n </span>\n {record !== undefined && (\n <span\n className={`stamp-imprint ${isAnimating ? \"stamp-press\" : \"\"}`}\n role=\"img\"\n aria-label={`Acquired at ${formatStampDate(record.acquiredAt)}`}\n >\n <span className=\"stamp-imprint__inner\">\n <span className=\"stamp-imprint__word\">STAMP</span>\n <span className=\"stamp-imprint__date\">{formatStampDate(record.acquiredAt)}</span>\n </span>\n </span>\n )}\n </button>\n );\n}\n\nexport interface StampSheetProps<TLocale extends string = SupportedLocale> {\n readonly title?: LocalizedText<TLocale>;\n readonly config: RallyConfig<TLocale> | PublicRallyConfig<TLocale>;\n readonly state?: StampRallyState | null;\n readonly progress?: StampRallyProgress;\n readonly presentations?: Readonly<Record<string, StampPresentation>>;\n readonly animatedStampId?: string | null;\n readonly disabled?: boolean;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly theme?: SheetTheme;\n readonly onStampSelect?: (stampId: string) => void;\n readonly adapter?: RallyViewerAdapter<TLocale>;\n}\n\nexport function StampSheet<TLocale extends string = SupportedLocale>({\n title,\n config,\n state = null,\n progress,\n presentations = {},\n animatedStampId = null,\n disabled = false,\n locale = \"ja\" as TLocale,\n dictionary,\n theme = config.theme ?? DEFAULT_SHEET_THEME,\n onStampSelect,\n adapter,\n}: StampSheetProps<TLocale>) {\n if (\"spots\" in config) {\n if (adapter === undefined)\n return (\n <RallyViewer\n config={config}\n locale={locale}\n {...(onStampSelect === undefined ? {} : { onSpotSelect: onStampSelect })}\n />\n );\n return (\n <RallyViewer\n config={config}\n adapter={adapter}\n locale={locale}\n {...(onStampSelect === undefined ? {} : { onSpotSelect: onStampSelect })}\n />\n );\n }\n const acquired = new Set(state?.records.map((record) => record.stampId) ?? []);\n const next = new Set(progress?.nextAvailableStamps.map((stamp) => stamp.id) ?? []);\n const count = progress?.acquired ?? acquired.size;\n const total = progress?.total ?? config.stamps.length;\n const percentage = progress?.percentage ?? (total === 0 ? 0 : (count / total) * 100);\n const style = {\n \"--stamp-primary\": `var(--stamprally-primary-override, ${theme.primaryColor})`,\n \"--stamp-bg\": `var(--stamprally-background-override, ${theme.backgroundColor ?? DEFAULT_SHEET_THEME.backgroundColor ?? \"#ffffff\"})`,\n \"--stamp-card-bg\": `var(--stamprally-card-override, ${theme.cardBackgroundColor})`,\n \"--stamp-text\": `var(--stamprally-text-override, ${theme.textColor})`,\n \"--stamp-grid-cols\": String(theme.gridColumns),\n \"--stamp-grid-cols-mobile\": String(Math.min(theme.gridColumns, 2)),\n \"--stamp-unclaimed-opacity\": String(theme.unclaimedOpacity ?? 1),\n \"--stamp-font-family\": FONT_STACKS[theme.fontFamily ?? \"serif\"],\n ...(theme.completedStampColor === undefined\n ? {}\n : { \"--stamp-completed-color\": theme.completedStampColor }),\n \"--stamprally-primary\": `var(--stamprally-primary-override, ${theme.primaryColor})`,\n \"--stamprally-background\": `var(--stamprally-background-override, ${theme.backgroundColor ?? \"transparent\"})`,\n \"--stamprally-card\": `var(--stamprally-card-override, ${theme.cardBackgroundColor})`,\n \"--stamprally-text\": `var(--stamprally-text-override, ${theme.textColor})`,\n \"--stamprally-columns\": String(theme.gridColumns),\n } as CSSProperties;\n const messages = {\n available: dictionary?.[locale]?.available ?? (locale === \"en\" ? \"available\" : \"取得可能\"),\n locked: dictionary?.[locale]?.locked ?? (locale === \"en\" ? \"locked\" : \"順序待ち\"),\n stamped: dictionary?.[locale]?.stamped ?? (locale === \"en\" ? \"stamped\" : \"取得済み\"),\n remaining: (value: number) =>\n dictionary?.[locale]?.remaining?.replace(\"{count}\", String(value)) ??\n (locale === \"en\" ? `${value} spots remaining` : `あと${value}箇所`),\n completed:\n dictionary?.[locale]?.completed ?? (locale === \"en\" ? \"RALLY COMPLETED\" : \"ラリー達成\"),\n };\n return (\n <section\n className={`stamp-sheet ${percentage >= 100 ? \"stamp-sheet--completed\" : \"\"}`}\n style={style}\n aria-label={resolveLocalizedText(title, locale) || config.id}\n >\n <header className=\"stamp-sheet__header\">\n <h2>{resolveLocalizedText(title, locale) || config.id}</h2>\n <span className=\"stamp-sheet__score\" role=\"status\" aria-live=\"polite\">\n {count} / {total}\n </span>\n </header>\n <div className=\"stamp-sheet__progress-label\">\n <span>{messages.remaining(Math.max(0, total - count))}</span>\n <strong>{Math.round(percentage)}%</strong>\n </div>\n <div\n className=\"stamp-sheet__progress-track\"\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(percentage)}\n aria-label={locale === \"en\" ? \"Rally progress\" : \"スタンプ取得進捗\"}\n >\n <span\n className=\"stamp-sheet__progress-fill\"\n style={{ display: \"block\", width: `${percentage}%` }}\n />\n </div>\n <div className=\"stamp-sheet__grid\">\n {config.stamps.map((stamp, index) => {\n const recordForStamp = state?.records.find((record) => record.stampId === stamp.id);\n return (\n <StampSlot\n key={stamp.id}\n stamp={stamp}\n {...(recordForStamp === undefined ? {} : { record: recordForStamp })}\n isNext={next.has(stamp.id)}\n slotNumber={index + 1}\n {...(presentations[stamp.id] === undefined\n ? {}\n : { presentation: presentations[stamp.id] })}\n isAnimating={animatedStampId === stamp.id}\n disabled={disabled}\n slotShape={theme.slotShape}\n locale={locale}\n {...(dictionary === undefined ? {} : { dictionary })}\n statusText={\n recordForStamp === undefined\n ? next.has(stamp.id)\n ? messages.available\n : messages.locked\n : messages.stamped\n }\n onSelect={() => onStampSelect?.(stamp.id)}\n />\n );\n })}\n </div>\n {percentage >= 100 && (\n <div className=\"stamp-sheet__complete-mark\" role=\"status\" aria-live=\"polite\">\n COMPLETE!!\n </div>\n )}\n {percentage >= 100 && (\n <div className=\"stamp-sheet__complete-message\">{messages.completed}</div>\n )}\n </section>\n );\n}\n\nexport interface AcquisitionFeedback {\n readonly ok: boolean;\n readonly message: string;\n}\nexport interface StampModalProps<TLocale extends string = SupportedLocale> {\n readonly open: boolean;\n readonly stamp: SpotItem<TLocale> | null;\n readonly record?: StampRallyState[\"records\"][number] | undefined;\n readonly presentation?: StampPresentation | null;\n readonly requiredStampName?: string | null;\n readonly isAvailable?: boolean;\n readonly isPending?: boolean;\n readonly isCompleted?: boolean;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly onClose: () => void;\n readonly onAcquire?: (\n stampId: string,\n context: VerificationContext,\n ) => Promise<AcquisitionFeedback>;\n readonly onCheckIn?: (\n stampId: string,\n context: VerificationContext,\n ) => Promise<AcquisitionFeedback>;\n readonly onNotify?: (feedback: AcquisitionFeedback) => void;\n}\n\nexport function StampModal<TLocale extends string = SupportedLocale>({\n open,\n stamp,\n record,\n isAvailable = true,\n isPending = false,\n locale = \"ja\" as TLocale,\n dictionary,\n onClose,\n onAcquire,\n onCheckIn,\n onNotify,\n}: StampModalProps<TLocale>) {\n const [token, setToken] = useState(\"\");\n const modalRef = useFocusTrap(open && stamp !== null, onClose, isPending);\n useEffect(() => {\n if (!open) setToken(\"\");\n }, [open]);\n if (!open || stamp === null) return null;\n const submit = async (context: VerificationContext): Promise<void> => {\n if (!isAvailable || record !== undefined) return;\n const handler = onAcquire ?? onCheckIn;\n if (handler === undefined) return;\n const feedback = await handler(stamp.id, context);\n onNotify?.(feedback);\n if (feedback.ok) onClose();\n };\n const name = resolveLocalizedText(stamp.name, locale);\n const messages = dictionary?.[locale] ?? {};\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"stamprally-modal-title\"\n className=\"stamprally-modal\"\n >\n <div className=\"stamprally-modal__panel\" ref={modalRef} tabIndex={-1}>\n <button\n type=\"button\"\n aria-label=\"Close stamp details\"\n aria-disabled={isPending}\n onClick={onClose}\n disabled={isPending}\n >\n ×\n </button>\n <h2 id=\"stamprally-modal-title\">{name}</h2>\n {record !== undefined ? (\n <p>{messages.alreadyClaimed ?? \"Already claimed.\"}</p>\n ) : (\n <p>{resolveLocalizedText(stamp.description, locale)}</p>\n )}\n {stamp.condition.type === \"token\" ? (\n <form\n onSubmit={(event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void submit({ type: \"token\", token });\n }}\n >\n <label>\n {messages.passcode ?? \"Passcode\"}{\" \"}\n <input value={token} onChange={(event) => setToken(event.target.value)} />\n </label>\n <button\n type=\"submit\"\n aria-label=\"Claim stamp\"\n aria-disabled={!isAvailable || isPending}\n disabled={!isAvailable || isPending}\n >\n {messages.claimStamp ?? \"Claim stamp\"}\n </button>\n </form>\n ) : (\n <button\n type=\"button\"\n aria-label=\"Claim stamp\"\n aria-disabled={!isAvailable || isPending}\n onClick={() => void submit({ type: \"instant\" })}\n disabled={!isAvailable || isPending}\n >\n {messages.claimStamp ?? \"Claim stamp\"}\n </button>\n )}\n </div>\n </div>\n );\n}\n\nexport interface RewardPanelProps<TLocale extends string = SupportedLocale> {\n readonly rewards: ReadonlyArray<RewardItem<TLocale>>;\n readonly states: ReadonlyArray<RewardState>;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly isPending?: boolean;\n readonly open?: boolean;\n readonly onClose?: () => void;\n readonly onRedeem: (\n rewardId: string,\n options?: { readonly passcode?: string; readonly staffId?: string },\n ) => Promise<ConsumeResult>;\n readonly onNotify?: (ok: boolean, message: string) => void;\n}\n\nexport function RewardPanel<TLocale extends string = SupportedLocale>({\n rewards,\n states,\n locale = \"ja\" as TLocale,\n dictionary,\n isPending = false,\n open = true,\n onClose,\n onRedeem,\n onNotify,\n}: RewardPanelProps<TLocale>) {\n const [passcodes, setPasscodes] = useState<Readonly<Record<string, string>>>({});\n const panelRef = useFocusTrap(open && onClose !== undefined, onClose, isPending);\n if (!open) return null;\n return (\n <section\n ref={panelRef}\n role=\"dialog\"\n aria-labelledby=\"stamprally-rewards-title\"\n aria-modal=\"true\"\n className=\"stamprally-rewards\"\n tabIndex={-1}\n >\n <header className=\"stamprally-rewards__header\">\n <h2 id=\"stamprally-rewards-title\">{dictionary?.[locale]?.rewards ?? \"Rewards\"}</h2>\n {onClose !== undefined && (\n <button\n type=\"button\"\n aria-label=\"Close rewards\"\n aria-disabled={isPending}\n disabled={isPending}\n onClick={onClose}\n >\n ×\n </button>\n )}\n </header>\n {rewards.map((reward) => {\n const state = states.find((item) => item.rewardId === reward.id);\n const available = state?.status === \"AVAILABLE\";\n const redeem = async (options?: { readonly passcode?: string }): Promise<void> => {\n const result = await onRedeem(reward.id, options);\n onNotify?.(\n result.ok,\n result.ok\n ? (dictionary?.[locale]?.rewardClaimed ?? \"Reward claimed.\")\n : result.error.code,\n );\n };\n return (\n <article\n key={reward.id}\n className={`stamprally-reward stamprally-reward--${state?.status ?? \"LOCKED\"}`}\n >\n <h3>{resolveLocalizedText(reward.title, locale)}</h3>\n <p>{resolveLocalizedText(reward.description, locale)}</p>\n <span role=\"status\" aria-live=\"polite\">\n {state?.status ?? \"LOCKED\"}\n </span>\n {reward.redemptionMethod === \"staff_passcode\" && (\n <form\n onSubmit={(event) => {\n event.preventDefault();\n void redeem({ passcode: passcodes[reward.id] ?? \"\" });\n }}\n >\n <label>\n {dictionary?.[locale]?.staffPasscode ?? \"Staff passcode\"}{\" \"}\n <input\n type=\"password\"\n value={passcodes[reward.id] ?? \"\"}\n onChange={(event) =>\n setPasscodes((current) => ({ ...current, [reward.id]: event.target.value }))\n }\n />\n </label>\n <button\n type=\"submit\"\n aria-label={`Redeem ${resolveLocalizedText(reward.title, locale)}`}\n aria-disabled={!available || isPending}\n disabled={!available || isPending}\n >\n {dictionary?.[locale]?.redeem ?? \"Redeem\"}\n </button>\n </form>\n )}\n {reward.redemptionMethod !== \"staff_passcode\" && (\n <button\n type=\"button\"\n aria-label={`Redeem ${resolveLocalizedText(reward.title, locale)}`}\n aria-disabled={!available || isPending}\n disabled={!available || isPending}\n onClick={() => void redeem()}\n >\n {dictionary?.[locale]?.redeem ?? \"Redeem\"}\n </button>\n )}\n </article>\n );\n })}\n </section>\n );\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,14 +1,23 @@
1
1
  import * as react from 'react';
2
- import { PublicRallyConfig, SupportedLocale, RewardItem, RewardState, LocaleDictionary, ConsumeResult, SpotItem, StampRallyState, VerificationContext, LocalizedText, RallyConfig, StampRallyProgress, SheetTheme, SlotShape } from '@stamprally/core';
2
+ import { PublicRallyConfig, UserRallyState, UniversalCheckInResult, ClaimOptions, UniversalClaimResult, UniversalStampRallyClient, SupportedLocale, RewardItem, RewardState, LocaleDictionary, ConsumeResult, SpotItem, StampRallyState, VerificationContext, LocalizedText, RallyConfig, StampRallyProgress, SheetTheme, SlotShape } from '@stamprally/core';
3
3
  export { LocaleDictionary } from '@stamprally/core';
4
4
 
5
- interface RallyViewerProps<TLocale extends string = string> {
5
+ interface RallyViewerAdapter<TLocale extends string = string> {
6
+ readonly state: UserRallyState;
6
7
  readonly config: PublicRallyConfig<TLocale>;
8
+ readonly onCheckIn: (spotId: string, proof: unknown) => Promise<UniversalCheckInResult>;
9
+ readonly onClaimReward: (rewardId: string, options?: ClaimOptions) => Promise<UniversalClaimResult>;
10
+ readonly onSync?: () => Promise<void>;
11
+ }
12
+ interface RallyViewerProps<TLocale extends string = string> {
13
+ readonly config?: PublicRallyConfig<TLocale>;
14
+ readonly adapter?: RallyViewerAdapter<TLocale>;
15
+ readonly client?: UniversalStampRallyClient;
7
16
  readonly locale?: TLocale;
8
17
  readonly onSpotSelect?: (spotId: string) => void;
9
18
  }
10
19
  /** Lightweight public-config viewer for applications that do not need the legacy StampSheet state model. */
11
- declare function RallyViewer<TLocale extends string = string>({ config, locale, onSpotSelect, }: RallyViewerProps<TLocale>): react.JSX.Element;
20
+ declare function RallyViewer<TLocale extends string = string>({ config, adapter, client, locale, onSpotSelect, }: RallyViewerProps<TLocale>): react.JSX.Element | null;
12
21
  interface StampPresentation {
13
22
  readonly label?: string;
14
23
  readonly icon?: string;
@@ -32,7 +41,7 @@ interface StampSlotProps<TLocale extends string = SupportedLocale> {
32
41
  declare function StampSlot<TLocale extends string = SupportedLocale>({ stamp, record, isNext, slotNumber, presentation, isAnimating, disabled, slotShape, locale, statusText, onSelect, }: StampSlotProps<TLocale>): react.JSX.Element;
33
42
  interface StampSheetProps<TLocale extends string = SupportedLocale> {
34
43
  readonly title?: LocalizedText<TLocale>;
35
- readonly config: RallyConfig<TLocale>;
44
+ readonly config: RallyConfig<TLocale> | PublicRallyConfig<TLocale>;
36
45
  readonly state?: StampRallyState | null;
37
46
  readonly progress?: StampRallyProgress;
38
47
  readonly presentations?: Readonly<Record<string, StampPresentation>>;
@@ -42,8 +51,9 @@ interface StampSheetProps<TLocale extends string = SupportedLocale> {
42
51
  readonly dictionary?: LocaleDictionary<TLocale>;
43
52
  readonly theme?: SheetTheme;
44
53
  readonly onStampSelect?: (stampId: string) => void;
54
+ readonly adapter?: RallyViewerAdapter<TLocale>;
45
55
  }
46
- declare function StampSheet<TLocale extends string = SupportedLocale>({ title, config, state, progress, presentations, animatedStampId, disabled, locale, dictionary, theme, onStampSelect, }: StampSheetProps<TLocale>): react.JSX.Element;
56
+ declare function StampSheet<TLocale extends string = SupportedLocale>({ title, config, state, progress, presentations, animatedStampId, disabled, locale, dictionary, theme, onStampSelect, adapter, }: StampSheetProps<TLocale>): react.JSX.Element;
47
57
  interface AcquisitionFeedback {
48
58
  readonly ok: boolean;
49
59
  readonly message: string;
@@ -81,4 +91,4 @@ interface RewardPanelProps<TLocale extends string = SupportedLocale> {
81
91
  }
82
92
  declare function RewardPanel<TLocale extends string = SupportedLocale>({ rewards, states, locale, dictionary, isPending, open, onClose, onRedeem, onNotify, }: RewardPanelProps<TLocale>): react.JSX.Element | null;
83
93
 
84
- export { type AcquisitionFeedback, RallyViewer, type RallyViewerProps, RewardPanel, type RewardPanelProps, StampModal, type StampModalProps, type StampPresentation, StampSheet, type StampSheetProps, StampSlot, type StampSlotProps };
94
+ export { type AcquisitionFeedback, RallyViewer, type RallyViewerAdapter, type RallyViewerProps, RewardPanel, type RewardPanelProps, StampModal, type StampModalProps, type StampPresentation, StampSheet, type StampSheetProps, StampSlot, type StampSlotProps };
package/dist/index.d.ts CHANGED
@@ -1,14 +1,23 @@
1
1
  import * as react from 'react';
2
- import { PublicRallyConfig, SupportedLocale, RewardItem, RewardState, LocaleDictionary, ConsumeResult, SpotItem, StampRallyState, VerificationContext, LocalizedText, RallyConfig, StampRallyProgress, SheetTheme, SlotShape } from '@stamprally/core';
2
+ import { PublicRallyConfig, UserRallyState, UniversalCheckInResult, ClaimOptions, UniversalClaimResult, UniversalStampRallyClient, SupportedLocale, RewardItem, RewardState, LocaleDictionary, ConsumeResult, SpotItem, StampRallyState, VerificationContext, LocalizedText, RallyConfig, StampRallyProgress, SheetTheme, SlotShape } from '@stamprally/core';
3
3
  export { LocaleDictionary } from '@stamprally/core';
4
4
 
5
- interface RallyViewerProps<TLocale extends string = string> {
5
+ interface RallyViewerAdapter<TLocale extends string = string> {
6
+ readonly state: UserRallyState;
6
7
  readonly config: PublicRallyConfig<TLocale>;
8
+ readonly onCheckIn: (spotId: string, proof: unknown) => Promise<UniversalCheckInResult>;
9
+ readonly onClaimReward: (rewardId: string, options?: ClaimOptions) => Promise<UniversalClaimResult>;
10
+ readonly onSync?: () => Promise<void>;
11
+ }
12
+ interface RallyViewerProps<TLocale extends string = string> {
13
+ readonly config?: PublicRallyConfig<TLocale>;
14
+ readonly adapter?: RallyViewerAdapter<TLocale>;
15
+ readonly client?: UniversalStampRallyClient;
7
16
  readonly locale?: TLocale;
8
17
  readonly onSpotSelect?: (spotId: string) => void;
9
18
  }
10
19
  /** Lightweight public-config viewer for applications that do not need the legacy StampSheet state model. */
11
- declare function RallyViewer<TLocale extends string = string>({ config, locale, onSpotSelect, }: RallyViewerProps<TLocale>): react.JSX.Element;
20
+ declare function RallyViewer<TLocale extends string = string>({ config, adapter, client, locale, onSpotSelect, }: RallyViewerProps<TLocale>): react.JSX.Element | null;
12
21
  interface StampPresentation {
13
22
  readonly label?: string;
14
23
  readonly icon?: string;
@@ -32,7 +41,7 @@ interface StampSlotProps<TLocale extends string = SupportedLocale> {
32
41
  declare function StampSlot<TLocale extends string = SupportedLocale>({ stamp, record, isNext, slotNumber, presentation, isAnimating, disabled, slotShape, locale, statusText, onSelect, }: StampSlotProps<TLocale>): react.JSX.Element;
33
42
  interface StampSheetProps<TLocale extends string = SupportedLocale> {
34
43
  readonly title?: LocalizedText<TLocale>;
35
- readonly config: RallyConfig<TLocale>;
44
+ readonly config: RallyConfig<TLocale> | PublicRallyConfig<TLocale>;
36
45
  readonly state?: StampRallyState | null;
37
46
  readonly progress?: StampRallyProgress;
38
47
  readonly presentations?: Readonly<Record<string, StampPresentation>>;
@@ -42,8 +51,9 @@ interface StampSheetProps<TLocale extends string = SupportedLocale> {
42
51
  readonly dictionary?: LocaleDictionary<TLocale>;
43
52
  readonly theme?: SheetTheme;
44
53
  readonly onStampSelect?: (stampId: string) => void;
54
+ readonly adapter?: RallyViewerAdapter<TLocale>;
45
55
  }
46
- declare function StampSheet<TLocale extends string = SupportedLocale>({ title, config, state, progress, presentations, animatedStampId, disabled, locale, dictionary, theme, onStampSelect, }: StampSheetProps<TLocale>): react.JSX.Element;
56
+ declare function StampSheet<TLocale extends string = SupportedLocale>({ title, config, state, progress, presentations, animatedStampId, disabled, locale, dictionary, theme, onStampSelect, adapter, }: StampSheetProps<TLocale>): react.JSX.Element;
47
57
  interface AcquisitionFeedback {
48
58
  readonly ok: boolean;
49
59
  readonly message: string;
@@ -81,4 +91,4 @@ interface RewardPanelProps<TLocale extends string = SupportedLocale> {
81
91
  }
82
92
  declare function RewardPanel<TLocale extends string = SupportedLocale>({ rewards, states, locale, dictionary, isPending, open, onClose, onRedeem, onNotify, }: RewardPanelProps<TLocale>): react.JSX.Element | null;
83
93
 
84
- export { type AcquisitionFeedback, RallyViewer, type RallyViewerProps, RewardPanel, type RewardPanelProps, StampModal, type StampModalProps, type StampPresentation, StampSheet, type StampSheetProps, StampSlot, type StampSlotProps };
94
+ export { type AcquisitionFeedback, RallyViewer, type RallyViewerAdapter, type RallyViewerProps, RewardPanel, type RewardPanelProps, StampModal, type StampModalProps, type StampPresentation, StampSheet, type StampSheetProps, StampSlot, type StampSlotProps };
package/dist/index.js CHANGED
@@ -5,19 +5,117 @@ import { jsxs, jsx } from 'react/jsx-runtime';
5
5
  // src/index.tsx
6
6
  function RallyViewer({
7
7
  config,
8
+ adapter,
9
+ client,
8
10
  locale,
9
11
  onSpotSelect
10
12
  }) {
11
13
  const activeLocale = locale ?? "en";
14
+ const resolvedConfig = adapter?.config ?? config ?? client?.getConfig();
15
+ const renderConfig = resolvedConfig ?? {
16
+ id: "empty",
17
+ title: "",
18
+ spots: [],
19
+ rewards: []
20
+ };
21
+ const emptyState = {
22
+ rallyId: renderConfig.id,
23
+ records: [],
24
+ updatedAt: (/* @__PURE__ */ new Date(0)).toISOString()
25
+ };
26
+ const resolvedState = adapter?.state ?? client?.getState() ?? emptyState;
27
+ const [selectedSpotId, setSelectedSpotId] = useState(null);
28
+ const [proof, setProof] = useState("");
29
+ const [feedback, setFeedback] = useState(null);
30
+ const [, setClientRevision] = useState(0);
31
+ useEffect(() => {
32
+ if (client === void 0) return;
33
+ return client.subscribe(() => setClientRevision((revision) => revision + 1));
34
+ }, [client]);
35
+ const selectedSpot = renderConfig.spots.find((spot) => spot.id === selectedSpotId);
36
+ const checkIn = adapter?.onCheckIn ?? (client === void 0 ? void 0 : (spotId, value) => client.checkIn(spotId, value));
37
+ const claimReward = adapter?.onClaimReward ?? (client === void 0 ? void 0 : (rewardId, options) => client.claimReward(rewardId, options));
38
+ const claimed = new Set(resolvedState.records.map((record) => record.stampId));
39
+ const submit = async () => {
40
+ if (selectedSpot === void 0 || checkIn === void 0) return;
41
+ const result = await checkIn(selectedSpot.id, proof);
42
+ setFeedback(result.ok ? "Check-in completed." : result.error.code);
43
+ if (result.ok) {
44
+ setProof("");
45
+ setSelectedSpotId(null);
46
+ }
47
+ };
48
+ if (resolvedConfig === void 0) return null;
12
49
  return /* @__PURE__ */ jsxs("section", { "aria-label": "Stamp rally viewer", className: "stamprally-viewer", children: [
13
50
  /* @__PURE__ */ jsxs("header", { children: [
14
- /* @__PURE__ */ jsx("h1", { children: resolveLocalizedText(config.title, activeLocale) }),
15
- config.description !== void 0 && /* @__PURE__ */ jsx("p", { children: resolveLocalizedText(config.description, activeLocale) })
51
+ /* @__PURE__ */ jsx("h1", { children: resolveLocalizedText(renderConfig.title, activeLocale) }),
52
+ renderConfig.description !== void 0 && /* @__PURE__ */ jsx("p", { children: resolveLocalizedText(renderConfig.description, activeLocale) }),
53
+ adapter?.onSync !== void 0 && /* @__PURE__ */ jsx("button", { type: "button", onClick: () => void adapter.onSync?.(), children: "Sync" })
16
54
  ] }),
17
- /* @__PURE__ */ jsx("ol", { children: config.spots.map((spot) => /* @__PURE__ */ jsxs("li", { children: [
18
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onSpotSelect?.(spot.id), children: resolveLocalizedText(spot.name, activeLocale) }),
55
+ /* @__PURE__ */ jsx("div", { role: "grid", "aria-label": "Stamp rally spots", children: renderConfig.spots.map((spot, index) => /* @__PURE__ */ jsxs("div", { children: [
56
+ /* @__PURE__ */ jsxs(
57
+ "button",
58
+ {
59
+ type: "button",
60
+ "aria-label": `${resolveLocalizedText(spot.name, activeLocale)}${claimed.has(spot.id) ? ", claimed" : ", available"}`,
61
+ onClick: () => {
62
+ onSpotSelect?.(spot.id);
63
+ setSelectedSpotId(spot.id);
64
+ setFeedback(null);
65
+ },
66
+ children: [
67
+ /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", children: [
68
+ "#",
69
+ String(index + 1).padStart(2, "0")
70
+ ] }),
71
+ " ",
72
+ resolveLocalizedText(spot.name, activeLocale)
73
+ ]
74
+ }
75
+ ),
19
76
  /* @__PURE__ */ jsx("span", { children: spot.conditions[0]?.type ?? "custom" })
20
- ] }, spot.id)) })
77
+ ] }, spot.id)) }),
78
+ /* @__PURE__ */ jsx("p", { role: "status", "aria-live": "polite", children: feedback ?? `${claimed.size} / ${renderConfig.spots.length} claimed` }),
79
+ /* @__PURE__ */ jsxs("section", { "aria-label": "Rewards", children: [
80
+ /* @__PURE__ */ jsx("h2", { children: "Rewards" }),
81
+ renderConfig.rewards.map((reward) => {
82
+ const rewardState = resolvedState.rewards?.find((item) => item.rewardId === reward.id);
83
+ const available = rewardState?.status === "AVAILABLE";
84
+ return /* @__PURE__ */ jsxs("article", { children: [
85
+ /* @__PURE__ */ jsx("h3", { children: resolveLocalizedText(reward.title, activeLocale) }),
86
+ /* @__PURE__ */ jsx("span", { children: rewardState?.status ?? "LOCKED" }),
87
+ claimReward !== void 0 && /* @__PURE__ */ jsx(
88
+ "button",
89
+ {
90
+ type: "button",
91
+ disabled: !available,
92
+ onClick: () => void claimReward(reward.id).then((result) => {
93
+ setFeedback(result.ok ? "Reward claimed." : result.error.code);
94
+ }),
95
+ children: "Claim reward"
96
+ }
97
+ )
98
+ ] }, reward.id);
99
+ })
100
+ ] }),
101
+ selectedSpot !== void 0 && checkIn !== void 0 && /* @__PURE__ */ jsxs("div", { role: "dialog", "aria-modal": "true", "aria-labelledby": "rally-viewer-spot-title", children: [
102
+ /* @__PURE__ */ jsx("h2", { id: "rally-viewer-spot-title", children: resolveLocalizedText(selectedSpot.name, activeLocale) }),
103
+ /* @__PURE__ */ jsx("p", { children: resolveLocalizedText(selectedSpot.description, activeLocale) }),
104
+ /* @__PURE__ */ jsxs("label", { children: [
105
+ "Proof",
106
+ /* @__PURE__ */ jsx("input", { value: proof, onChange: (event) => setProof(event.target.value) })
107
+ ] }),
108
+ /* @__PURE__ */ jsx(
109
+ "button",
110
+ {
111
+ type: "button",
112
+ onClick: () => void submit(),
113
+ disabled: claimed.has(selectedSpot.id),
114
+ children: "Check in"
115
+ }
116
+ ),
117
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setSelectedSpotId(null), children: "Close" })
118
+ ] })
21
119
  ] });
22
120
  }
23
121
  function useFocusTrap(active, onClose, closeDisabled = false) {
@@ -144,8 +242,29 @@ function StampSheet({
144
242
  locale = "ja",
145
243
  dictionary,
146
244
  theme = config.theme ?? DEFAULT_SHEET_THEME,
147
- onStampSelect
245
+ onStampSelect,
246
+ adapter
148
247
  }) {
248
+ if ("spots" in config) {
249
+ if (adapter === void 0)
250
+ return /* @__PURE__ */ jsx(
251
+ RallyViewer,
252
+ {
253
+ config,
254
+ locale,
255
+ ...onStampSelect === void 0 ? {} : { onSpotSelect: onStampSelect }
256
+ }
257
+ );
258
+ return /* @__PURE__ */ jsx(
259
+ RallyViewer,
260
+ {
261
+ config,
262
+ adapter,
263
+ locale,
264
+ ...onStampSelect === void 0 ? {} : { onSpotSelect: onStampSelect }
265
+ }
266
+ );
267
+ }
149
268
  const acquired = new Set(state?.records.map((record) => record.stampId) ?? []);
150
269
  const next = new Set(progress?.nextAvailableStamps.map((stamp) => stamp.id) ?? []);
151
270
  const count = progress?.acquired ?? acquired.size;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import {\n type ConsumeResult,\n DEFAULT_SHEET_THEME,\n type LocaleDictionary,\n type LocalizedText,\n type PublicRallyConfig,\n type RallyConfig,\n type RewardItem,\n type RewardState,\n resolveLocalizedText,\n type SheetTheme,\n type SlotShape,\n type SpotItem,\n type StampRallyProgress,\n type StampRallyState,\n type SupportedLocale,\n type VerificationContext,\n} from \"@stamprally/core\";\nimport type { CSSProperties, FormEvent, RefObject } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport type { LocaleDictionary } from \"@stamprally/core\";\n\nexport interface RallyViewerProps<TLocale extends string = string> {\n readonly config: PublicRallyConfig<TLocale>;\n readonly locale?: TLocale;\n readonly onSpotSelect?: (spotId: string) => void;\n}\n\n/** Lightweight public-config viewer for applications that do not need the legacy StampSheet state model. */\nexport function RallyViewer<TLocale extends string = string>({\n config,\n locale,\n onSpotSelect,\n}: RallyViewerProps<TLocale>) {\n const activeLocale = locale ?? (\"en\" as TLocale);\n return (\n <section aria-label=\"Stamp rally viewer\" className=\"stamprally-viewer\">\n <header>\n <h1>{resolveLocalizedText(config.title, activeLocale)}</h1>\n {config.description !== undefined && (\n <p>{resolveLocalizedText(config.description, activeLocale)}</p>\n )}\n </header>\n <ol>\n {config.spots.map((spot) => (\n <li key={spot.id}>\n <button type=\"button\" onClick={() => onSpotSelect?.(spot.id)}>\n {resolveLocalizedText(spot.name, activeLocale)}\n </button>\n <span>{spot.conditions[0]?.type ?? \"custom\"}</span>\n </li>\n ))}\n </ol>\n </section>\n );\n}\n\nfunction useFocusTrap(\n active: boolean,\n onClose: (() => void) | undefined,\n closeDisabled = false,\n): RefObject<HTMLDivElement | null> {\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n if (!active) return;\n const container = containerRef.current;\n if (container === null) return;\n\n const focusableSelector =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n const focusable = (): ReadonlyArray<HTMLElement> =>\n Array.from(container.querySelectorAll<HTMLElement>(focusableSelector));\n const first = focusable()[0];\n first?.focus();\n\n const handleKeyDown = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n if (!closeDisabled) {\n event.preventDefault();\n onClose?.();\n }\n return;\n }\n if (event.key !== \"Tab\") return;\n\n const elements = focusable();\n if (elements.length === 0) {\n event.preventDefault();\n container.focus();\n return;\n }\n const firstElement = elements[0];\n const lastElement = elements[elements.length - 1];\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement?.focus();\n } else if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault();\n firstElement?.focus();\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [active, closeDisabled, onClose]);\n\n return containerRef;\n}\n\nexport interface StampPresentation {\n readonly label?: string;\n readonly icon?: string;\n readonly ink?: \"vermilion\" | \"indigo\";\n readonly channel?: \"instant\" | \"qr\" | \"nfc\" | \"geo\";\n}\n\nexport interface StampSlotProps<TLocale extends string = SupportedLocale> {\n readonly stamp: SpotItem<TLocale>;\n readonly record?: StampRallyState[\"records\"][number] | undefined;\n readonly isNext?: boolean;\n readonly slotNumber?: number;\n readonly presentation?: StampPresentation | undefined;\n readonly isAnimating?: boolean;\n readonly disabled?: boolean;\n readonly slotShape?: SlotShape;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly statusText?: string;\n readonly onSelect?: () => void;\n}\n\nconst FONT_STACKS: Readonly<Record<NonNullable<SheetTheme[\"fontFamily\"]>, string>> = {\n \"system-ui\": 'system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif',\n serif: 'Georgia, \"Times New Roman\", \"Yu Mincho\", serif',\n \"rounded-sans\": '\"Arial Rounded MT Bold\", \"Hiragino Maru Gothic ProN\", \"Yu Gothic\", sans-serif',\n monospace: 'ui-monospace, SFMono-Regular, Consolas, \"Liberation Mono\", monospace',\n handwritten: '\"Segoe Print\", \"Bradley Hand\", \"Comic Sans MS\", cursive',\n};\n\nfunction formatStampDate(value: string): string {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value;\n const pad = (part: number) => String(part).padStart(2, \"0\");\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;\n}\n\nexport function StampSlot<TLocale extends string = SupportedLocale>({\n stamp,\n record,\n isNext = false,\n slotNumber = 1,\n presentation = {},\n isAnimating = false,\n disabled = false,\n slotShape = \"rounded\",\n locale = \"ja\" as TLocale,\n statusText,\n onSelect,\n}: StampSlotProps<TLocale>) {\n const status = record === undefined ? (isNext ? \"available\" : \"locked\") : \"stamped\";\n const resolvedStatus = statusText ?? status;\n const statusSeparator = statusText !== undefined && locale === \"ja\" ? \"、\" : \", \";\n const name = resolveLocalizedText(stamp.name, locale);\n const label = presentation.label ?? stamp.condition.type;\n return (\n <button\n type=\"button\"\n disabled={disabled}\n onClick={onSelect}\n aria-label={`#${String(slotNumber).padStart(2, \"0\")} ${name}${statusSeparator}${resolvedStatus}`}\n aria-disabled={disabled}\n data-status={status}\n data-shape={slotShape}\n className={`stamp-slot stamp-slot--${status} stamp-slot--${presentation.ink ?? \"vermilion\"} stamp-slot--shape-${slotShape}${isAnimating ? \" stamp-slot--animating\" : \"\"}`}\n style={{ \"--stamp-primary\": \"var(--stamprally-primary, #9e551e)\" } as CSSProperties}\n >\n <span className=\"stamp-slot__topline\">\n <span className=\"stamp-slot__number\">#{String(slotNumber).padStart(2, \"0\")}</span>\n <span className={`stamp-slot__state stamp-slot__state--${status}`}>{resolvedStatus}</span>\n </span>\n <span className=\"stamp-slot__watermark\" aria-hidden=\"true\">\n {presentation.icon ?? \"✦\"}\n </span>\n <span className=\"stamp-slot__name\">{name}</span>\n <span className=\"stamp-slot__condition\">\n <span aria-hidden=\"true\">{presentation.icon ?? \"✦\"}</span>\n {label}\n </span>\n {record !== undefined && (\n <span\n className={`stamp-imprint ${isAnimating ? \"stamp-press\" : \"\"}`}\n role=\"img\"\n aria-label={`Acquired at ${formatStampDate(record.acquiredAt)}`}\n >\n <span className=\"stamp-imprint__inner\">\n <span className=\"stamp-imprint__word\">STAMP</span>\n <span className=\"stamp-imprint__date\">{formatStampDate(record.acquiredAt)}</span>\n </span>\n </span>\n )}\n </button>\n );\n}\n\nexport interface StampSheetProps<TLocale extends string = SupportedLocale> {\n readonly title?: LocalizedText<TLocale>;\n readonly config: RallyConfig<TLocale>;\n readonly state?: StampRallyState | null;\n readonly progress?: StampRallyProgress;\n readonly presentations?: Readonly<Record<string, StampPresentation>>;\n readonly animatedStampId?: string | null;\n readonly disabled?: boolean;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly theme?: SheetTheme;\n readonly onStampSelect?: (stampId: string) => void;\n}\n\nexport function StampSheet<TLocale extends string = SupportedLocale>({\n title,\n config,\n state = null,\n progress,\n presentations = {},\n animatedStampId = null,\n disabled = false,\n locale = \"ja\" as TLocale,\n dictionary,\n theme = config.theme ?? DEFAULT_SHEET_THEME,\n onStampSelect,\n}: StampSheetProps<TLocale>) {\n const acquired = new Set(state?.records.map((record) => record.stampId) ?? []);\n const next = new Set(progress?.nextAvailableStamps.map((stamp) => stamp.id) ?? []);\n const count = progress?.acquired ?? acquired.size;\n const total = progress?.total ?? config.stamps.length;\n const percentage = progress?.percentage ?? (total === 0 ? 0 : (count / total) * 100);\n const style = {\n \"--stamp-primary\": `var(--stamprally-primary-override, ${theme.primaryColor})`,\n \"--stamp-bg\": `var(--stamprally-background-override, ${theme.backgroundColor ?? DEFAULT_SHEET_THEME.backgroundColor ?? \"#ffffff\"})`,\n \"--stamp-card-bg\": `var(--stamprally-card-override, ${theme.cardBackgroundColor})`,\n \"--stamp-text\": `var(--stamprally-text-override, ${theme.textColor})`,\n \"--stamp-grid-cols\": String(theme.gridColumns),\n \"--stamp-grid-cols-mobile\": String(Math.min(theme.gridColumns, 2)),\n \"--stamp-unclaimed-opacity\": String(theme.unclaimedOpacity ?? 1),\n \"--stamp-font-family\": FONT_STACKS[theme.fontFamily ?? \"serif\"],\n ...(theme.completedStampColor === undefined\n ? {}\n : { \"--stamp-completed-color\": theme.completedStampColor }),\n \"--stamprally-primary\": `var(--stamprally-primary-override, ${theme.primaryColor})`,\n \"--stamprally-background\": `var(--stamprally-background-override, ${theme.backgroundColor ?? \"transparent\"})`,\n \"--stamprally-card\": `var(--stamprally-card-override, ${theme.cardBackgroundColor})`,\n \"--stamprally-text\": `var(--stamprally-text-override, ${theme.textColor})`,\n \"--stamprally-columns\": String(theme.gridColumns),\n } as CSSProperties;\n const messages = {\n available: dictionary?.[locale]?.available ?? (locale === \"en\" ? \"available\" : \"取得可能\"),\n locked: dictionary?.[locale]?.locked ?? (locale === \"en\" ? \"locked\" : \"順序待ち\"),\n stamped: dictionary?.[locale]?.stamped ?? (locale === \"en\" ? \"stamped\" : \"取得済み\"),\n remaining: (value: number) =>\n dictionary?.[locale]?.remaining?.replace(\"{count}\", String(value)) ??\n (locale === \"en\" ? `${value} spots remaining` : `あと${value}箇所`),\n completed:\n dictionary?.[locale]?.completed ?? (locale === \"en\" ? \"RALLY COMPLETED\" : \"ラリー達成\"),\n };\n return (\n <section\n className={`stamp-sheet ${percentage >= 100 ? \"stamp-sheet--completed\" : \"\"}`}\n style={style}\n aria-label={resolveLocalizedText(title, locale) || config.id}\n >\n <header className=\"stamp-sheet__header\">\n <h2>{resolveLocalizedText(title, locale) || config.id}</h2>\n <span className=\"stamp-sheet__score\" role=\"status\" aria-live=\"polite\">\n {count} / {total}\n </span>\n </header>\n <div className=\"stamp-sheet__progress-label\">\n <span>{messages.remaining(Math.max(0, total - count))}</span>\n <strong>{Math.round(percentage)}%</strong>\n </div>\n <div\n className=\"stamp-sheet__progress-track\"\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(percentage)}\n aria-label={locale === \"en\" ? \"Rally progress\" : \"スタンプ取得進捗\"}\n >\n <span\n className=\"stamp-sheet__progress-fill\"\n style={{ display: \"block\", width: `${percentage}%` }}\n />\n </div>\n <div className=\"stamp-sheet__grid\">\n {config.stamps.map((stamp, index) => {\n const recordForStamp = state?.records.find((record) => record.stampId === stamp.id);\n return (\n <StampSlot\n key={stamp.id}\n stamp={stamp}\n {...(recordForStamp === undefined ? {} : { record: recordForStamp })}\n isNext={next.has(stamp.id)}\n slotNumber={index + 1}\n {...(presentations[stamp.id] === undefined\n ? {}\n : { presentation: presentations[stamp.id] })}\n isAnimating={animatedStampId === stamp.id}\n disabled={disabled}\n slotShape={theme.slotShape}\n locale={locale}\n {...(dictionary === undefined ? {} : { dictionary })}\n statusText={\n recordForStamp === undefined\n ? next.has(stamp.id)\n ? messages.available\n : messages.locked\n : messages.stamped\n }\n onSelect={() => onStampSelect?.(stamp.id)}\n />\n );\n })}\n </div>\n {percentage >= 100 && (\n <div className=\"stamp-sheet__complete-mark\" role=\"status\" aria-live=\"polite\">\n COMPLETE!!\n </div>\n )}\n {percentage >= 100 && (\n <div className=\"stamp-sheet__complete-message\">{messages.completed}</div>\n )}\n </section>\n );\n}\n\nexport interface AcquisitionFeedback {\n readonly ok: boolean;\n readonly message: string;\n}\nexport interface StampModalProps<TLocale extends string = SupportedLocale> {\n readonly open: boolean;\n readonly stamp: SpotItem<TLocale> | null;\n readonly record?: StampRallyState[\"records\"][number] | undefined;\n readonly presentation?: StampPresentation | null;\n readonly requiredStampName?: string | null;\n readonly isAvailable?: boolean;\n readonly isPending?: boolean;\n readonly isCompleted?: boolean;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly onClose: () => void;\n readonly onAcquire?: (\n stampId: string,\n context: VerificationContext,\n ) => Promise<AcquisitionFeedback>;\n readonly onCheckIn?: (\n stampId: string,\n context: VerificationContext,\n ) => Promise<AcquisitionFeedback>;\n readonly onNotify?: (feedback: AcquisitionFeedback) => void;\n}\n\nexport function StampModal<TLocale extends string = SupportedLocale>({\n open,\n stamp,\n record,\n isAvailable = true,\n isPending = false,\n locale = \"ja\" as TLocale,\n dictionary,\n onClose,\n onAcquire,\n onCheckIn,\n onNotify,\n}: StampModalProps<TLocale>) {\n const [token, setToken] = useState(\"\");\n const modalRef = useFocusTrap(open && stamp !== null, onClose, isPending);\n useEffect(() => {\n if (!open) setToken(\"\");\n }, [open]);\n if (!open || stamp === null) return null;\n const submit = async (context: VerificationContext): Promise<void> => {\n if (!isAvailable || record !== undefined) return;\n const handler = onAcquire ?? onCheckIn;\n if (handler === undefined) return;\n const feedback = await handler(stamp.id, context);\n onNotify?.(feedback);\n if (feedback.ok) onClose();\n };\n const name = resolveLocalizedText(stamp.name, locale);\n const messages = dictionary?.[locale] ?? {};\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"stamprally-modal-title\"\n className=\"stamprally-modal\"\n >\n <div className=\"stamprally-modal__panel\" ref={modalRef} tabIndex={-1}>\n <button\n type=\"button\"\n aria-label=\"Close stamp details\"\n aria-disabled={isPending}\n onClick={onClose}\n disabled={isPending}\n >\n ×\n </button>\n <h2 id=\"stamprally-modal-title\">{name}</h2>\n {record !== undefined ? (\n <p>{messages.alreadyClaimed ?? \"Already claimed.\"}</p>\n ) : (\n <p>{resolveLocalizedText(stamp.description, locale)}</p>\n )}\n {stamp.condition.type === \"token\" ? (\n <form\n onSubmit={(event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void submit({ type: \"token\", token });\n }}\n >\n <label>\n {messages.passcode ?? \"Passcode\"}{\" \"}\n <input value={token} onChange={(event) => setToken(event.target.value)} />\n </label>\n <button\n type=\"submit\"\n aria-label=\"Claim stamp\"\n aria-disabled={!isAvailable || isPending}\n disabled={!isAvailable || isPending}\n >\n {messages.claimStamp ?? \"Claim stamp\"}\n </button>\n </form>\n ) : (\n <button\n type=\"button\"\n aria-label=\"Claim stamp\"\n aria-disabled={!isAvailable || isPending}\n onClick={() => void submit({ type: \"instant\" })}\n disabled={!isAvailable || isPending}\n >\n {messages.claimStamp ?? \"Claim stamp\"}\n </button>\n )}\n </div>\n </div>\n );\n}\n\nexport interface RewardPanelProps<TLocale extends string = SupportedLocale> {\n readonly rewards: ReadonlyArray<RewardItem<TLocale>>;\n readonly states: ReadonlyArray<RewardState>;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly isPending?: boolean;\n readonly open?: boolean;\n readonly onClose?: () => void;\n readonly onRedeem: (\n rewardId: string,\n options?: { readonly passcode?: string; readonly staffId?: string },\n ) => Promise<ConsumeResult>;\n readonly onNotify?: (ok: boolean, message: string) => void;\n}\n\nexport function RewardPanel<TLocale extends string = SupportedLocale>({\n rewards,\n states,\n locale = \"ja\" as TLocale,\n dictionary,\n isPending = false,\n open = true,\n onClose,\n onRedeem,\n onNotify,\n}: RewardPanelProps<TLocale>) {\n const [passcodes, setPasscodes] = useState<Readonly<Record<string, string>>>({});\n const panelRef = useFocusTrap(open && onClose !== undefined, onClose, isPending);\n if (!open) return null;\n return (\n <section\n ref={panelRef}\n role=\"dialog\"\n aria-labelledby=\"stamprally-rewards-title\"\n aria-modal=\"true\"\n className=\"stamprally-rewards\"\n tabIndex={-1}\n >\n <header className=\"stamprally-rewards__header\">\n <h2 id=\"stamprally-rewards-title\">{dictionary?.[locale]?.rewards ?? \"Rewards\"}</h2>\n {onClose !== undefined && (\n <button\n type=\"button\"\n aria-label=\"Close rewards\"\n aria-disabled={isPending}\n disabled={isPending}\n onClick={onClose}\n >\n ×\n </button>\n )}\n </header>\n {rewards.map((reward) => {\n const state = states.find((item) => item.rewardId === reward.id);\n const available = state?.status === \"AVAILABLE\";\n const redeem = async (options?: { readonly passcode?: string }): Promise<void> => {\n const result = await onRedeem(reward.id, options);\n onNotify?.(\n result.ok,\n result.ok\n ? (dictionary?.[locale]?.rewardClaimed ?? \"Reward claimed.\")\n : result.error.code,\n );\n };\n return (\n <article\n key={reward.id}\n className={`stamprally-reward stamprally-reward--${state?.status ?? \"LOCKED\"}`}\n >\n <h3>{resolveLocalizedText(reward.title, locale)}</h3>\n <p>{resolveLocalizedText(reward.description, locale)}</p>\n <span role=\"status\" aria-live=\"polite\">\n {state?.status ?? \"LOCKED\"}\n </span>\n {reward.redemptionMethod === \"staff_passcode\" && (\n <form\n onSubmit={(event) => {\n event.preventDefault();\n void redeem({ passcode: passcodes[reward.id] ?? \"\" });\n }}\n >\n <label>\n {dictionary?.[locale]?.staffPasscode ?? \"Staff passcode\"}{\" \"}\n <input\n type=\"password\"\n value={passcodes[reward.id] ?? \"\"}\n onChange={(event) =>\n setPasscodes((current) => ({ ...current, [reward.id]: event.target.value }))\n }\n />\n </label>\n <button\n type=\"submit\"\n aria-label={`Redeem ${resolveLocalizedText(reward.title, locale)}`}\n aria-disabled={!available || isPending}\n disabled={!available || isPending}\n >\n {dictionary?.[locale]?.redeem ?? \"Redeem\"}\n </button>\n </form>\n )}\n {reward.redemptionMethod !== \"staff_passcode\" && (\n <button\n type=\"button\"\n aria-label={`Redeem ${resolveLocalizedText(reward.title, locale)}`}\n aria-disabled={!available || isPending}\n disabled={!available || isPending}\n onClick={() => void redeem()}\n >\n {dictionary?.[locale]?.redeem ?? \"Redeem\"}\n </button>\n )}\n </article>\n );\n })}\n </section>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import {\n type ClaimOptions,\n type ConsumeResult,\n DEFAULT_SHEET_THEME,\n type LocaleDictionary,\n type LocalizedText,\n type PublicRallyConfig,\n type RallyConfig,\n type RewardItem,\n type RewardState,\n resolveLocalizedText,\n type SheetTheme,\n type SlotShape,\n type SpotItem,\n type StampRallyProgress,\n type StampRallyState,\n type SupportedLocale,\n type UniversalCheckInResult,\n type UniversalClaimResult,\n type UniversalStampRallyClient,\n type UserRallyState,\n type VerificationContext,\n} from \"@stamprally/core\";\nimport type { CSSProperties, FormEvent, RefObject } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nexport type { LocaleDictionary } from \"@stamprally/core\";\n\nexport interface RallyViewerAdapter<TLocale extends string = string> {\n readonly state: UserRallyState;\n readonly config: PublicRallyConfig<TLocale>;\n readonly onCheckIn: (spotId: string, proof: unknown) => Promise<UniversalCheckInResult>;\n readonly onClaimReward: (\n rewardId: string,\n options?: ClaimOptions,\n ) => Promise<UniversalClaimResult>;\n readonly onSync?: () => Promise<void>;\n}\n\nexport interface RallyViewerProps<TLocale extends string = string> {\n readonly config?: PublicRallyConfig<TLocale>;\n readonly adapter?: RallyViewerAdapter<TLocale>;\n readonly client?: UniversalStampRallyClient;\n readonly locale?: TLocale;\n readonly onSpotSelect?: (spotId: string) => void;\n}\n\n/** Lightweight public-config viewer for applications that do not need the legacy StampSheet state model. */\nexport function RallyViewer<TLocale extends string = string>({\n config,\n adapter,\n client,\n locale,\n onSpotSelect,\n}: RallyViewerProps<TLocale>) {\n const activeLocale = locale ?? (\"en\" as TLocale);\n const resolvedConfig = adapter?.config ?? config ?? client?.getConfig();\n const renderConfig: PublicRallyConfig<TLocale> = resolvedConfig ?? {\n id: \"empty\",\n version: \"0.7.0\",\n title: \"\",\n spots: [],\n rewards: [],\n };\n const emptyState: UserRallyState = {\n rallyId: renderConfig.id,\n records: [],\n updatedAt: new Date(0).toISOString(),\n };\n const resolvedState = adapter?.state ?? client?.getState() ?? emptyState;\n const [selectedSpotId, setSelectedSpotId] = useState<string | null>(null);\n const [proof, setProof] = useState(\"\");\n const [feedback, setFeedback] = useState<string | null>(null);\n const [, setClientRevision] = useState(0);\n useEffect(() => {\n if (client === undefined) return;\n return client.subscribe(() => setClientRevision((revision) => revision + 1));\n }, [client]);\n const selectedSpot = renderConfig.spots.find((spot) => spot.id === selectedSpotId);\n const checkIn =\n adapter?.onCheckIn ??\n (client === undefined\n ? undefined\n : (spotId: string, value: unknown) => client.checkIn(spotId, value));\n const claimReward =\n adapter?.onClaimReward ??\n (client === undefined\n ? undefined\n : (rewardId: string, options?: ClaimOptions) => client.claimReward(rewardId, options));\n const claimed = new Set(resolvedState.records.map((record) => record.stampId));\n const submit = async (): Promise<void> => {\n if (selectedSpot === undefined || checkIn === undefined) return;\n const result = await checkIn(selectedSpot.id, proof);\n setFeedback(result.ok ? \"Check-in completed.\" : result.error.code);\n if (result.ok) {\n setProof(\"\");\n setSelectedSpotId(null);\n }\n };\n if (resolvedConfig === undefined) return null;\n return (\n <section aria-label=\"Stamp rally viewer\" className=\"stamprally-viewer\">\n <header>\n <h1>{resolveLocalizedText(renderConfig.title, activeLocale)}</h1>\n {renderConfig.description !== undefined && (\n <p>{resolveLocalizedText(renderConfig.description, activeLocale)}</p>\n )}\n {adapter?.onSync !== undefined && (\n <button type=\"button\" onClick={() => void adapter.onSync?.()}>\n Sync\n </button>\n )}\n </header>\n {/* biome-ignore lint/a11y/useSemanticElements: The viewer exposes the requested ARIA grid contract. */}\n <div role=\"grid\" aria-label=\"Stamp rally spots\">\n {renderConfig.spots.map((spot, index) => (\n <div key={spot.id}>\n <button\n type=\"button\"\n aria-label={`${resolveLocalizedText(spot.name, activeLocale)}${claimed.has(spot.id) ? \", claimed\" : \", available\"}`}\n onClick={() => {\n onSpotSelect?.(spot.id);\n setSelectedSpotId(spot.id);\n setFeedback(null);\n }}\n >\n <span aria-hidden=\"true\">#{String(index + 1).padStart(2, \"0\")}</span>{\" \"}\n {resolveLocalizedText(spot.name, activeLocale)}\n </button>\n <span>{spot.conditions[0]?.type ?? \"custom\"}</span>\n </div>\n ))}\n </div>\n <p role=\"status\" aria-live=\"polite\">\n {feedback ?? `${claimed.size} / ${renderConfig.spots.length} claimed`}\n </p>\n <section aria-label=\"Rewards\">\n <h2>Rewards</h2>\n {renderConfig.rewards.map((reward) => {\n const rewardState = resolvedState.rewards?.find((item) => item.rewardId === reward.id);\n const available = rewardState?.status === \"AVAILABLE\";\n return (\n <article key={reward.id}>\n <h3>{resolveLocalizedText(reward.title, activeLocale)}</h3>\n <span>{rewardState?.status ?? \"LOCKED\"}</span>\n {claimReward !== undefined && (\n <button\n type=\"button\"\n disabled={!available}\n onClick={() =>\n void claimReward(reward.id).then((result) => {\n setFeedback(result.ok ? \"Reward claimed.\" : result.error.code);\n })\n }\n >\n Claim reward\n </button>\n )}\n </article>\n );\n })}\n </section>\n {selectedSpot !== undefined && checkIn !== undefined && (\n <div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"rally-viewer-spot-title\">\n <h2 id=\"rally-viewer-spot-title\">\n {resolveLocalizedText(selectedSpot.name, activeLocale)}\n </h2>\n <p>{resolveLocalizedText(selectedSpot.description, activeLocale)}</p>\n <label>\n Proof\n <input value={proof} onChange={(event) => setProof(event.target.value)} />\n </label>\n <button\n type=\"button\"\n onClick={() => void submit()}\n disabled={claimed.has(selectedSpot.id)}\n >\n Check in\n </button>\n <button type=\"button\" onClick={() => setSelectedSpotId(null)}>\n Close\n </button>\n </div>\n )}\n </section>\n );\n}\n\nfunction useFocusTrap(\n active: boolean,\n onClose: (() => void) | undefined,\n closeDisabled = false,\n): RefObject<HTMLDivElement | null> {\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n if (!active) return;\n const container = containerRef.current;\n if (container === null) return;\n\n const focusableSelector =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n const focusable = (): ReadonlyArray<HTMLElement> =>\n Array.from(container.querySelectorAll<HTMLElement>(focusableSelector));\n const first = focusable()[0];\n first?.focus();\n\n const handleKeyDown = (event: KeyboardEvent): void => {\n if (event.key === \"Escape\") {\n if (!closeDisabled) {\n event.preventDefault();\n onClose?.();\n }\n return;\n }\n if (event.key !== \"Tab\") return;\n\n const elements = focusable();\n if (elements.length === 0) {\n event.preventDefault();\n container.focus();\n return;\n }\n const firstElement = elements[0];\n const lastElement = elements[elements.length - 1];\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement?.focus();\n } else if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault();\n firstElement?.focus();\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [active, closeDisabled, onClose]);\n\n return containerRef;\n}\n\nexport interface StampPresentation {\n readonly label?: string;\n readonly icon?: string;\n readonly ink?: \"vermilion\" | \"indigo\";\n readonly channel?: \"instant\" | \"qr\" | \"nfc\" | \"geo\";\n}\n\nexport interface StampSlotProps<TLocale extends string = SupportedLocale> {\n readonly stamp: SpotItem<TLocale>;\n readonly record?: StampRallyState[\"records\"][number] | undefined;\n readonly isNext?: boolean;\n readonly slotNumber?: number;\n readonly presentation?: StampPresentation | undefined;\n readonly isAnimating?: boolean;\n readonly disabled?: boolean;\n readonly slotShape?: SlotShape;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly statusText?: string;\n readonly onSelect?: () => void;\n}\n\nconst FONT_STACKS: Readonly<Record<NonNullable<SheetTheme[\"fontFamily\"]>, string>> = {\n \"system-ui\": 'system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif',\n serif: 'Georgia, \"Times New Roman\", \"Yu Mincho\", serif',\n \"rounded-sans\": '\"Arial Rounded MT Bold\", \"Hiragino Maru Gothic ProN\", \"Yu Gothic\", sans-serif',\n monospace: 'ui-monospace, SFMono-Regular, Consolas, \"Liberation Mono\", monospace',\n handwritten: '\"Segoe Print\", \"Bradley Hand\", \"Comic Sans MS\", cursive',\n};\n\nfunction formatStampDate(value: string): string {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value;\n const pad = (part: number) => String(part).padStart(2, \"0\");\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;\n}\n\nexport function StampSlot<TLocale extends string = SupportedLocale>({\n stamp,\n record,\n isNext = false,\n slotNumber = 1,\n presentation = {},\n isAnimating = false,\n disabled = false,\n slotShape = \"rounded\",\n locale = \"ja\" as TLocale,\n statusText,\n onSelect,\n}: StampSlotProps<TLocale>) {\n const status = record === undefined ? (isNext ? \"available\" : \"locked\") : \"stamped\";\n const resolvedStatus = statusText ?? status;\n const statusSeparator = statusText !== undefined && locale === \"ja\" ? \"、\" : \", \";\n const name = resolveLocalizedText(stamp.name, locale);\n const label = presentation.label ?? stamp.condition.type;\n return (\n <button\n type=\"button\"\n disabled={disabled}\n onClick={onSelect}\n aria-label={`#${String(slotNumber).padStart(2, \"0\")} ${name}${statusSeparator}${resolvedStatus}`}\n aria-disabled={disabled}\n data-status={status}\n data-shape={slotShape}\n className={`stamp-slot stamp-slot--${status} stamp-slot--${presentation.ink ?? \"vermilion\"} stamp-slot--shape-${slotShape}${isAnimating ? \" stamp-slot--animating\" : \"\"}`}\n style={{ \"--stamp-primary\": \"var(--stamprally-primary, #9e551e)\" } as CSSProperties}\n >\n <span className=\"stamp-slot__topline\">\n <span className=\"stamp-slot__number\">#{String(slotNumber).padStart(2, \"0\")}</span>\n <span className={`stamp-slot__state stamp-slot__state--${status}`}>{resolvedStatus}</span>\n </span>\n <span className=\"stamp-slot__watermark\" aria-hidden=\"true\">\n {presentation.icon ?? \"✦\"}\n </span>\n <span className=\"stamp-slot__name\">{name}</span>\n <span className=\"stamp-slot__condition\">\n <span aria-hidden=\"true\">{presentation.icon ?? \"✦\"}</span>\n {label}\n </span>\n {record !== undefined && (\n <span\n className={`stamp-imprint ${isAnimating ? \"stamp-press\" : \"\"}`}\n role=\"img\"\n aria-label={`Acquired at ${formatStampDate(record.acquiredAt)}`}\n >\n <span className=\"stamp-imprint__inner\">\n <span className=\"stamp-imprint__word\">STAMP</span>\n <span className=\"stamp-imprint__date\">{formatStampDate(record.acquiredAt)}</span>\n </span>\n </span>\n )}\n </button>\n );\n}\n\nexport interface StampSheetProps<TLocale extends string = SupportedLocale> {\n readonly title?: LocalizedText<TLocale>;\n readonly config: RallyConfig<TLocale> | PublicRallyConfig<TLocale>;\n readonly state?: StampRallyState | null;\n readonly progress?: StampRallyProgress;\n readonly presentations?: Readonly<Record<string, StampPresentation>>;\n readonly animatedStampId?: string | null;\n readonly disabled?: boolean;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly theme?: SheetTheme;\n readonly onStampSelect?: (stampId: string) => void;\n readonly adapter?: RallyViewerAdapter<TLocale>;\n}\n\nexport function StampSheet<TLocale extends string = SupportedLocale>({\n title,\n config,\n state = null,\n progress,\n presentations = {},\n animatedStampId = null,\n disabled = false,\n locale = \"ja\" as TLocale,\n dictionary,\n theme = config.theme ?? DEFAULT_SHEET_THEME,\n onStampSelect,\n adapter,\n}: StampSheetProps<TLocale>) {\n if (\"spots\" in config) {\n if (adapter === undefined)\n return (\n <RallyViewer\n config={config}\n locale={locale}\n {...(onStampSelect === undefined ? {} : { onSpotSelect: onStampSelect })}\n />\n );\n return (\n <RallyViewer\n config={config}\n adapter={adapter}\n locale={locale}\n {...(onStampSelect === undefined ? {} : { onSpotSelect: onStampSelect })}\n />\n );\n }\n const acquired = new Set(state?.records.map((record) => record.stampId) ?? []);\n const next = new Set(progress?.nextAvailableStamps.map((stamp) => stamp.id) ?? []);\n const count = progress?.acquired ?? acquired.size;\n const total = progress?.total ?? config.stamps.length;\n const percentage = progress?.percentage ?? (total === 0 ? 0 : (count / total) * 100);\n const style = {\n \"--stamp-primary\": `var(--stamprally-primary-override, ${theme.primaryColor})`,\n \"--stamp-bg\": `var(--stamprally-background-override, ${theme.backgroundColor ?? DEFAULT_SHEET_THEME.backgroundColor ?? \"#ffffff\"})`,\n \"--stamp-card-bg\": `var(--stamprally-card-override, ${theme.cardBackgroundColor})`,\n \"--stamp-text\": `var(--stamprally-text-override, ${theme.textColor})`,\n \"--stamp-grid-cols\": String(theme.gridColumns),\n \"--stamp-grid-cols-mobile\": String(Math.min(theme.gridColumns, 2)),\n \"--stamp-unclaimed-opacity\": String(theme.unclaimedOpacity ?? 1),\n \"--stamp-font-family\": FONT_STACKS[theme.fontFamily ?? \"serif\"],\n ...(theme.completedStampColor === undefined\n ? {}\n : { \"--stamp-completed-color\": theme.completedStampColor }),\n \"--stamprally-primary\": `var(--stamprally-primary-override, ${theme.primaryColor})`,\n \"--stamprally-background\": `var(--stamprally-background-override, ${theme.backgroundColor ?? \"transparent\"})`,\n \"--stamprally-card\": `var(--stamprally-card-override, ${theme.cardBackgroundColor})`,\n \"--stamprally-text\": `var(--stamprally-text-override, ${theme.textColor})`,\n \"--stamprally-columns\": String(theme.gridColumns),\n } as CSSProperties;\n const messages = {\n available: dictionary?.[locale]?.available ?? (locale === \"en\" ? \"available\" : \"取得可能\"),\n locked: dictionary?.[locale]?.locked ?? (locale === \"en\" ? \"locked\" : \"順序待ち\"),\n stamped: dictionary?.[locale]?.stamped ?? (locale === \"en\" ? \"stamped\" : \"取得済み\"),\n remaining: (value: number) =>\n dictionary?.[locale]?.remaining?.replace(\"{count}\", String(value)) ??\n (locale === \"en\" ? `${value} spots remaining` : `あと${value}箇所`),\n completed:\n dictionary?.[locale]?.completed ?? (locale === \"en\" ? \"RALLY COMPLETED\" : \"ラリー達成\"),\n };\n return (\n <section\n className={`stamp-sheet ${percentage >= 100 ? \"stamp-sheet--completed\" : \"\"}`}\n style={style}\n aria-label={resolveLocalizedText(title, locale) || config.id}\n >\n <header className=\"stamp-sheet__header\">\n <h2>{resolveLocalizedText(title, locale) || config.id}</h2>\n <span className=\"stamp-sheet__score\" role=\"status\" aria-live=\"polite\">\n {count} / {total}\n </span>\n </header>\n <div className=\"stamp-sheet__progress-label\">\n <span>{messages.remaining(Math.max(0, total - count))}</span>\n <strong>{Math.round(percentage)}%</strong>\n </div>\n <div\n className=\"stamp-sheet__progress-track\"\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(percentage)}\n aria-label={locale === \"en\" ? \"Rally progress\" : \"スタンプ取得進捗\"}\n >\n <span\n className=\"stamp-sheet__progress-fill\"\n style={{ display: \"block\", width: `${percentage}%` }}\n />\n </div>\n <div className=\"stamp-sheet__grid\">\n {config.stamps.map((stamp, index) => {\n const recordForStamp = state?.records.find((record) => record.stampId === stamp.id);\n return (\n <StampSlot\n key={stamp.id}\n stamp={stamp}\n {...(recordForStamp === undefined ? {} : { record: recordForStamp })}\n isNext={next.has(stamp.id)}\n slotNumber={index + 1}\n {...(presentations[stamp.id] === undefined\n ? {}\n : { presentation: presentations[stamp.id] })}\n isAnimating={animatedStampId === stamp.id}\n disabled={disabled}\n slotShape={theme.slotShape}\n locale={locale}\n {...(dictionary === undefined ? {} : { dictionary })}\n statusText={\n recordForStamp === undefined\n ? next.has(stamp.id)\n ? messages.available\n : messages.locked\n : messages.stamped\n }\n onSelect={() => onStampSelect?.(stamp.id)}\n />\n );\n })}\n </div>\n {percentage >= 100 && (\n <div className=\"stamp-sheet__complete-mark\" role=\"status\" aria-live=\"polite\">\n COMPLETE!!\n </div>\n )}\n {percentage >= 100 && (\n <div className=\"stamp-sheet__complete-message\">{messages.completed}</div>\n )}\n </section>\n );\n}\n\nexport interface AcquisitionFeedback {\n readonly ok: boolean;\n readonly message: string;\n}\nexport interface StampModalProps<TLocale extends string = SupportedLocale> {\n readonly open: boolean;\n readonly stamp: SpotItem<TLocale> | null;\n readonly record?: StampRallyState[\"records\"][number] | undefined;\n readonly presentation?: StampPresentation | null;\n readonly requiredStampName?: string | null;\n readonly isAvailable?: boolean;\n readonly isPending?: boolean;\n readonly isCompleted?: boolean;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly onClose: () => void;\n readonly onAcquire?: (\n stampId: string,\n context: VerificationContext,\n ) => Promise<AcquisitionFeedback>;\n readonly onCheckIn?: (\n stampId: string,\n context: VerificationContext,\n ) => Promise<AcquisitionFeedback>;\n readonly onNotify?: (feedback: AcquisitionFeedback) => void;\n}\n\nexport function StampModal<TLocale extends string = SupportedLocale>({\n open,\n stamp,\n record,\n isAvailable = true,\n isPending = false,\n locale = \"ja\" as TLocale,\n dictionary,\n onClose,\n onAcquire,\n onCheckIn,\n onNotify,\n}: StampModalProps<TLocale>) {\n const [token, setToken] = useState(\"\");\n const modalRef = useFocusTrap(open && stamp !== null, onClose, isPending);\n useEffect(() => {\n if (!open) setToken(\"\");\n }, [open]);\n if (!open || stamp === null) return null;\n const submit = async (context: VerificationContext): Promise<void> => {\n if (!isAvailable || record !== undefined) return;\n const handler = onAcquire ?? onCheckIn;\n if (handler === undefined) return;\n const feedback = await handler(stamp.id, context);\n onNotify?.(feedback);\n if (feedback.ok) onClose();\n };\n const name = resolveLocalizedText(stamp.name, locale);\n const messages = dictionary?.[locale] ?? {};\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"stamprally-modal-title\"\n className=\"stamprally-modal\"\n >\n <div className=\"stamprally-modal__panel\" ref={modalRef} tabIndex={-1}>\n <button\n type=\"button\"\n aria-label=\"Close stamp details\"\n aria-disabled={isPending}\n onClick={onClose}\n disabled={isPending}\n >\n ×\n </button>\n <h2 id=\"stamprally-modal-title\">{name}</h2>\n {record !== undefined ? (\n <p>{messages.alreadyClaimed ?? \"Already claimed.\"}</p>\n ) : (\n <p>{resolveLocalizedText(stamp.description, locale)}</p>\n )}\n {stamp.condition.type === \"token\" ? (\n <form\n onSubmit={(event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void submit({ type: \"token\", token });\n }}\n >\n <label>\n {messages.passcode ?? \"Passcode\"}{\" \"}\n <input value={token} onChange={(event) => setToken(event.target.value)} />\n </label>\n <button\n type=\"submit\"\n aria-label=\"Claim stamp\"\n aria-disabled={!isAvailable || isPending}\n disabled={!isAvailable || isPending}\n >\n {messages.claimStamp ?? \"Claim stamp\"}\n </button>\n </form>\n ) : (\n <button\n type=\"button\"\n aria-label=\"Claim stamp\"\n aria-disabled={!isAvailable || isPending}\n onClick={() => void submit({ type: \"instant\" })}\n disabled={!isAvailable || isPending}\n >\n {messages.claimStamp ?? \"Claim stamp\"}\n </button>\n )}\n </div>\n </div>\n );\n}\n\nexport interface RewardPanelProps<TLocale extends string = SupportedLocale> {\n readonly rewards: ReadonlyArray<RewardItem<TLocale>>;\n readonly states: ReadonlyArray<RewardState>;\n readonly locale?: TLocale;\n readonly dictionary?: LocaleDictionary<TLocale>;\n readonly isPending?: boolean;\n readonly open?: boolean;\n readonly onClose?: () => void;\n readonly onRedeem: (\n rewardId: string,\n options?: { readonly passcode?: string; readonly staffId?: string },\n ) => Promise<ConsumeResult>;\n readonly onNotify?: (ok: boolean, message: string) => void;\n}\n\nexport function RewardPanel<TLocale extends string = SupportedLocale>({\n rewards,\n states,\n locale = \"ja\" as TLocale,\n dictionary,\n isPending = false,\n open = true,\n onClose,\n onRedeem,\n onNotify,\n}: RewardPanelProps<TLocale>) {\n const [passcodes, setPasscodes] = useState<Readonly<Record<string, string>>>({});\n const panelRef = useFocusTrap(open && onClose !== undefined, onClose, isPending);\n if (!open) return null;\n return (\n <section\n ref={panelRef}\n role=\"dialog\"\n aria-labelledby=\"stamprally-rewards-title\"\n aria-modal=\"true\"\n className=\"stamprally-rewards\"\n tabIndex={-1}\n >\n <header className=\"stamprally-rewards__header\">\n <h2 id=\"stamprally-rewards-title\">{dictionary?.[locale]?.rewards ?? \"Rewards\"}</h2>\n {onClose !== undefined && (\n <button\n type=\"button\"\n aria-label=\"Close rewards\"\n aria-disabled={isPending}\n disabled={isPending}\n onClick={onClose}\n >\n ×\n </button>\n )}\n </header>\n {rewards.map((reward) => {\n const state = states.find((item) => item.rewardId === reward.id);\n const available = state?.status === \"AVAILABLE\";\n const redeem = async (options?: { readonly passcode?: string }): Promise<void> => {\n const result = await onRedeem(reward.id, options);\n onNotify?.(\n result.ok,\n result.ok\n ? (dictionary?.[locale]?.rewardClaimed ?? \"Reward claimed.\")\n : result.error.code,\n );\n };\n return (\n <article\n key={reward.id}\n className={`stamprally-reward stamprally-reward--${state?.status ?? \"LOCKED\"}`}\n >\n <h3>{resolveLocalizedText(reward.title, locale)}</h3>\n <p>{resolveLocalizedText(reward.description, locale)}</p>\n <span role=\"status\" aria-live=\"polite\">\n {state?.status ?? \"LOCKED\"}\n </span>\n {reward.redemptionMethod === \"staff_passcode\" && (\n <form\n onSubmit={(event) => {\n event.preventDefault();\n void redeem({ passcode: passcodes[reward.id] ?? \"\" });\n }}\n >\n <label>\n {dictionary?.[locale]?.staffPasscode ?? \"Staff passcode\"}{\" \"}\n <input\n type=\"password\"\n value={passcodes[reward.id] ?? \"\"}\n onChange={(event) =>\n setPasscodes((current) => ({ ...current, [reward.id]: event.target.value }))\n }\n />\n </label>\n <button\n type=\"submit\"\n aria-label={`Redeem ${resolveLocalizedText(reward.title, locale)}`}\n aria-disabled={!available || isPending}\n disabled={!available || isPending}\n >\n {dictionary?.[locale]?.redeem ?? \"Redeem\"}\n </button>\n </form>\n )}\n {reward.redemptionMethod !== \"staff_passcode\" && (\n <button\n type=\"button\"\n aria-label={`Redeem ${resolveLocalizedText(reward.title, locale)}`}\n aria-disabled={!available || isPending}\n disabled={!available || isPending}\n onClick={() => void redeem()}\n >\n {dictionary?.[locale]?.redeem ?? \"Redeem\"}\n </button>\n )}\n </article>\n );\n })}\n </section>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamprally/ui",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Accessible participant UI components for stamp rallies.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,8 +29,8 @@
29
29
  "./styles.css": "./dist/index.css"
30
30
  },
31
31
  "dependencies": {
32
- "@stamprally/core": "0.7.0",
33
- "@stamprally/react": "0.7.0"
32
+ "@stamprally/core": "0.8.0",
33
+ "@stamprally/react": "0.8.0"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "react": "^18.0.0 || ^19.0.0",