@stamprally/ui 0.2.1 → 0.3.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 +110 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +116 -0
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +110 -31
- package/dist/index.js.map +1 -1
- package/package.json +6 -7
- package/src/styles.css +0 -45
package/dist/index.cjs
CHANGED
|
@@ -5,6 +5,19 @@ var react = require('react');
|
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
|
|
7
7
|
// src/index.tsx
|
|
8
|
+
var FONT_STACKS = {
|
|
9
|
+
"system-ui": 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
10
|
+
serif: 'Georgia, "Times New Roman", "Yu Mincho", serif',
|
|
11
|
+
"rounded-sans": '"Arial Rounded MT Bold", "Hiragino Maru Gothic ProN", "Yu Gothic", sans-serif',
|
|
12
|
+
monospace: 'ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace',
|
|
13
|
+
handwritten: '"Segoe Print", "Bradley Hand", "Comic Sans MS", cursive'
|
|
14
|
+
};
|
|
15
|
+
function formatStampDate(value) {
|
|
16
|
+
const date = new Date(value);
|
|
17
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
18
|
+
const pad = (part) => String(part).padStart(2, "0");
|
|
19
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
20
|
+
}
|
|
8
21
|
function StampSlot({
|
|
9
22
|
stamp,
|
|
10
23
|
record,
|
|
@@ -15,9 +28,12 @@ function StampSlot({
|
|
|
15
28
|
disabled = false,
|
|
16
29
|
slotShape = "rounded",
|
|
17
30
|
locale = "ja",
|
|
31
|
+
statusText,
|
|
18
32
|
onSelect
|
|
19
33
|
}) {
|
|
20
34
|
const status = record === void 0 ? isNext ? "available" : "locked" : "stamped";
|
|
35
|
+
const resolvedStatus = statusText ?? status;
|
|
36
|
+
const statusSeparator = statusText !== void 0 && locale === "ja" ? "\u3001" : ", ";
|
|
21
37
|
const name = core.resolveLocalizedText(stamp.name, locale);
|
|
22
38
|
const label = presentation.label ?? stamp.condition.type;
|
|
23
39
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -26,16 +42,37 @@ function StampSlot({
|
|
|
26
42
|
type: "button",
|
|
27
43
|
disabled,
|
|
28
44
|
onClick: onSelect,
|
|
29
|
-
"aria-label":
|
|
45
|
+
"aria-label": `#${String(slotNumber).padStart(2, "0")} ${name}${statusSeparator}${resolvedStatus}`,
|
|
30
46
|
"data-status": status,
|
|
31
47
|
"data-shape": slotShape,
|
|
32
|
-
className: `stamp-slot stamp-slot--${status}${isAnimating ? " stamp-slot--animating" : ""}`,
|
|
48
|
+
className: `stamp-slot stamp-slot--${status} stamp-slot--${presentation.ink ?? "vermilion"} stamp-slot--shape-${slotShape}${isAnimating ? " stamp-slot--animating" : ""}`,
|
|
33
49
|
style: { "--stamp-primary": "var(--stamprally-primary, #9e551e)" },
|
|
34
50
|
children: [
|
|
35
|
-
/* @__PURE__ */ jsxRuntime.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "stamp-slot__topline", children: [
|
|
52
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "stamp-slot__number", children: [
|
|
53
|
+
"#",
|
|
54
|
+
String(slotNumber).padStart(2, "0")
|
|
55
|
+
] }),
|
|
56
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `stamp-slot__state stamp-slot__state--${status}`, children: resolvedStatus })
|
|
57
|
+
] }),
|
|
58
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "stamp-slot__watermark", "aria-hidden": "true", children: presentation.icon ?? "\u2726" }),
|
|
59
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "stamp-slot__name", children: name }),
|
|
60
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "stamp-slot__condition", children: [
|
|
61
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: presentation.icon ?? "\u2726" }),
|
|
62
|
+
label
|
|
63
|
+
] }),
|
|
64
|
+
record !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
65
|
+
"span",
|
|
66
|
+
{
|
|
67
|
+
className: `stamp-imprint ${isAnimating ? "stamp-press" : ""}`,
|
|
68
|
+
role: "img",
|
|
69
|
+
"aria-label": `Acquired at ${formatStampDate(record.acquiredAt)}`,
|
|
70
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "stamp-imprint__inner", children: [
|
|
71
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "stamp-imprint__word", children: "STAMP" }),
|
|
72
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "stamp-imprint__date", children: formatStampDate(record.acquiredAt) })
|
|
73
|
+
] })
|
|
74
|
+
}
|
|
75
|
+
)
|
|
39
76
|
]
|
|
40
77
|
}
|
|
41
78
|
);
|
|
@@ -58,54 +95,96 @@ function StampSheet({
|
|
|
58
95
|
const total = progress?.total ?? config.stamps.length;
|
|
59
96
|
const percentage = progress?.percentage ?? (total === 0 ? 0 : count / total * 100);
|
|
60
97
|
const style = {
|
|
61
|
-
"--
|
|
62
|
-
"--
|
|
63
|
-
"--
|
|
64
|
-
"--
|
|
98
|
+
"--stamp-primary": `var(--stamprally-primary-override, ${theme.primaryColor})`,
|
|
99
|
+
"--stamp-bg": `var(--stamprally-background-override, ${theme.backgroundColor ?? core.DEFAULT_SHEET_THEME.backgroundColor ?? "#ffffff"})`,
|
|
100
|
+
"--stamp-card-bg": `var(--stamprally-card-override, ${theme.cardBackgroundColor})`,
|
|
101
|
+
"--stamp-text": `var(--stamprally-text-override, ${theme.textColor})`,
|
|
102
|
+
"--stamp-grid-cols": String(theme.gridColumns),
|
|
103
|
+
"--stamp-grid-cols-mobile": String(Math.min(theme.gridColumns, 2)),
|
|
104
|
+
"--stamp-unclaimed-opacity": String(theme.unclaimedOpacity ?? 1),
|
|
105
|
+
"--stamp-font-family": FONT_STACKS[theme.fontFamily ?? "serif"],
|
|
106
|
+
...theme.completedStampColor === void 0 ? {} : { "--stamp-completed-color": theme.completedStampColor },
|
|
107
|
+
"--stamprally-primary": `var(--stamprally-primary-override, ${theme.primaryColor})`,
|
|
108
|
+
"--stamprally-background": `var(--stamprally-background-override, ${theme.backgroundColor ?? "transparent"})`,
|
|
109
|
+
"--stamprally-card": `var(--stamprally-card-override, ${theme.cardBackgroundColor})`,
|
|
110
|
+
"--stamprally-text": `var(--stamprally-text-override, ${theme.textColor})`,
|
|
65
111
|
"--stamprally-columns": String(theme.gridColumns)
|
|
66
112
|
};
|
|
113
|
+
const messages = locale === "en" ? {
|
|
114
|
+
available: "available",
|
|
115
|
+
locked: "locked",
|
|
116
|
+
stamped: "stamped",
|
|
117
|
+
remaining: (value) => `${value} spots remaining`,
|
|
118
|
+
completed: "RALLY COMPLETED"
|
|
119
|
+
} : {
|
|
120
|
+
available: "\u53D6\u5F97\u53EF\u80FD",
|
|
121
|
+
locked: "\u9806\u5E8F\u5F85\u3061",
|
|
122
|
+
stamped: "\u53D6\u5F97\u6E08\u307F",
|
|
123
|
+
remaining: (value) => `\u3042\u3068${value}\u7B87\u6240`,
|
|
124
|
+
completed: "\u30E9\u30EA\u30FC\u9054\u6210"
|
|
125
|
+
};
|
|
67
126
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
68
127
|
"section",
|
|
69
128
|
{
|
|
70
|
-
className: "
|
|
129
|
+
className: `stamp-sheet ${percentage >= 100 ? "stamp-sheet--completed" : ""}`,
|
|
71
130
|
style,
|
|
72
131
|
"aria-label": core.resolveLocalizedText(title, locale) || config.id,
|
|
73
132
|
children: [
|
|
74
|
-
/* @__PURE__ */ jsxRuntime.jsxs("header", { children: [
|
|
133
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "stamp-sheet__header", children: [
|
|
75
134
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { children: core.resolveLocalizedText(title, locale) || config.id }),
|
|
76
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { "aria-live": "polite", children: [
|
|
135
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "stamp-sheet__score", "aria-live": "polite", children: [
|
|
77
136
|
count,
|
|
78
137
|
" / ",
|
|
79
138
|
total
|
|
80
139
|
] })
|
|
81
140
|
] }),
|
|
141
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "stamp-sheet__progress-label", children: [
|
|
142
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: messages.remaining(Math.max(0, total - count)) }),
|
|
143
|
+
/* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
|
|
144
|
+
Math.round(percentage),
|
|
145
|
+
"%"
|
|
146
|
+
] })
|
|
147
|
+
] }),
|
|
82
148
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
83
149
|
"div",
|
|
84
150
|
{
|
|
151
|
+
className: "stamp-sheet__progress-track",
|
|
85
152
|
role: "progressbar",
|
|
86
153
|
"aria-valuemin": 0,
|
|
87
154
|
"aria-valuemax": 100,
|
|
88
155
|
"aria-valuenow": Math.round(percentage),
|
|
89
|
-
"aria-label": "Rally progress",
|
|
90
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
156
|
+
"aria-label": locale === "en" ? "Rally progress" : "\u30B9\u30BF\u30F3\u30D7\u53D6\u5F97\u9032\u6357",
|
|
157
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
158
|
+
"span",
|
|
159
|
+
{
|
|
160
|
+
className: "stamp-sheet__progress-fill",
|
|
161
|
+
style: { display: "block", width: `${percentage}%` }
|
|
162
|
+
}
|
|
163
|
+
)
|
|
91
164
|
}
|
|
92
165
|
),
|
|
93
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
166
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "stamp-sheet__grid", children: config.stamps.map((stamp, index) => {
|
|
167
|
+
const recordForStamp = state?.records.find((record) => record.stampId === stamp.id);
|
|
168
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
169
|
+
StampSlot,
|
|
170
|
+
{
|
|
171
|
+
stamp,
|
|
172
|
+
...recordForStamp === void 0 ? {} : { record: recordForStamp },
|
|
173
|
+
isNext: next.has(stamp.id),
|
|
174
|
+
slotNumber: index + 1,
|
|
175
|
+
...presentations[stamp.id] === void 0 ? {} : { presentation: presentations[stamp.id] },
|
|
176
|
+
isAnimating: animatedStampId === stamp.id,
|
|
177
|
+
disabled,
|
|
178
|
+
slotShape: theme.slotShape,
|
|
179
|
+
locale,
|
|
180
|
+
statusText: recordForStamp === void 0 ? next.has(stamp.id) ? messages.available : messages.locked : messages.stamped,
|
|
181
|
+
onSelect: () => onStampSelect?.(stamp.id)
|
|
182
|
+
},
|
|
183
|
+
stamp.id
|
|
184
|
+
);
|
|
185
|
+
}) }),
|
|
186
|
+
percentage >= 100 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "stamp-sheet__complete-mark", children: "COMPLETE!!" }),
|
|
187
|
+
percentage >= 100 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "stamp-sheet__complete-message", children: messages.completed })
|
|
109
188
|
]
|
|
110
189
|
}
|
|
111
190
|
);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.tsx"],"names":["resolveLocalizedText","jsxs","jsx","DEFAULT_SHEET_THEME","useState","useEffect"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n type ConsumeResult,\n DEFAULT_SHEET_THEME,\n type LocalizedText,\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 } from \"react\";\nimport { useEffect, useState } from \"react\";\n\nexport interface StampPresentation {\n readonly label?: string;\n readonly icon?: string;\n readonly ink?: \"vermilion\" | \"indigo\";\n}\n\nexport interface StampSlotProps {\n readonly stamp: SpotItem;\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?: SupportedLocale;\n readonly onSelect?: () => void;\n}\n\nexport function StampSlot({\n stamp,\n record,\n isNext = false,\n slotNumber = 1,\n presentation = {},\n isAnimating = false,\n disabled = false,\n slotShape = \"rounded\",\n locale = \"ja\",\n onSelect,\n}: StampSlotProps) {\n const status = record === undefined ? (isNext ? \"available\" : \"locked\") : \"stamped\";\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={`${slotNumber}. ${name} (${status})`}\n data-status={status}\n data-shape={slotShape}\n className={`stamp-slot stamp-slot--${status}${isAnimating ? \" stamp-slot--animating\" : \"\"}`}\n style={{ \"--stamp-primary\": \"var(--stamprally-primary, #9e551e)\" } as CSSProperties}\n >\n <span aria-hidden=\"true\">{presentation.icon ?? \"✦\"}</span>\n <strong>{name}</strong>\n <small>{label}</small>\n {record !== undefined && <time dateTime={record.acquiredAt}>{record.acquiredAt}</time>}\n </button>\n );\n}\n\nexport interface StampSheetProps {\n readonly title?: LocalizedText;\n readonly config: RallyConfig;\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?: SupportedLocale;\n readonly theme?: SheetTheme;\n readonly onStampSelect?: (stampId: string) => void;\n}\n\nexport function StampSheet({\n title,\n config,\n state = null,\n progress,\n presentations = {},\n animatedStampId = null,\n disabled = false,\n locale = \"ja\",\n theme = config.theme ?? DEFAULT_SHEET_THEME,\n onStampSelect,\n}: StampSheetProps) {\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 \"--stamprally-primary\": theme.primaryColor,\n \"--stamprally-background\": theme.backgroundColor ?? \"transparent\",\n \"--stamprally-card\": theme.cardBackgroundColor,\n \"--stamprally-text\": theme.textColor,\n \"--stamprally-columns\": String(theme.gridColumns),\n } as CSSProperties;\n return (\n <section\n className=\"stamprally-sheet\"\n style={style}\n aria-label={resolveLocalizedText(title, locale) || config.id}\n >\n <header>\n <h2>{resolveLocalizedText(title, locale) || config.id}</h2>\n <span aria-live=\"polite\">\n {count} / {total}\n </span>\n </header>\n <div\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(percentage)}\n aria-label=\"Rally progress\"\n >\n <span style={{ display: \"block\", width: `${percentage}%` }} />\n </div>\n <div className=\"stamprally-sheet__grid\">\n {config.stamps.map((stamp, index) => (\n <StampSlot\n key={stamp.id}\n stamp={stamp}\n {...(state?.records.find((record) => record.stampId === stamp.id) === undefined\n ? {}\n : { record: state?.records.find((record) => record.stampId === stamp.id) })}\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 onSelect={() => onStampSelect?.(stamp.id)}\n />\n ))}\n </div>\n </section>\n );\n}\n\nexport interface AcquisitionFeedback {\n readonly ok: boolean;\n readonly message: string;\n}\nexport interface StampModalProps {\n readonly open: boolean;\n readonly stamp: SpotItem | 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?: SupportedLocale;\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({\n open,\n stamp,\n record,\n isAvailable = true,\n isPending = false,\n locale = \"ja\",\n onClose,\n onAcquire,\n onCheckIn,\n onNotify,\n}: StampModalProps) {\n const [token, setToken] = useState(\"\");\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 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\">\n <button type=\"button\" aria-label=\"Close\" onClick={onClose} disabled={isPending}>\n ×\n </button>\n <h2 id=\"stamprally-modal-title\">{name}</h2>\n {record !== undefined ? (\n <p>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 Passcode <input value={token} onChange={(event) => setToken(event.target.value)} />\n </label>\n <button type=\"submit\" disabled={!isAvailable || isPending}>\n Claim stamp\n </button>\n </form>\n ) : (\n <button\n type=\"button\"\n onClick={() => void submit({ type: \"instant\" })}\n disabled={!isAvailable || isPending}\n >\n Claim stamp\n </button>\n )}\n </div>\n </div>\n );\n}\n\nexport interface RewardPanelProps {\n readonly rewards: ReadonlyArray<RewardItem>;\n readonly states: ReadonlyArray<RewardState>;\n readonly locale?: SupportedLocale;\n readonly isPending?: boolean;\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({\n rewards,\n states,\n locale = \"ja\",\n isPending = false,\n onRedeem,\n onNotify,\n}: RewardPanelProps) {\n const [passcodes, setPasscodes] = useState<Readonly<Record<string, string>>>({});\n return (\n <section aria-labelledby=\"stamprally-rewards-title\" className=\"stamprally-rewards\">\n <h2 id=\"stamprally-rewards-title\">Rewards</h2>\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?.(result.ok, result.ok ? \"Reward claimed.\" : result.error.code);\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>{state?.status ?? \"LOCKED\"}</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 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 type=\"submit\" disabled={!available || isPending}>\n Redeem\n </button>\n </form>\n )}\n {reward.redemptionMethod !== \"staff_passcode\" && (\n <button\n type=\"button\"\n disabled={!available || isPending}\n onClick={() => void redeem()}\n >\n Redeem\n </button>\n )}\n </article>\n );\n })}\n </section>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"names":["resolveLocalizedText","jsxs","jsx","DEFAULT_SHEET_THEME","useState","useEffect"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n type ConsumeResult,\n DEFAULT_SHEET_THEME,\n type LocalizedText,\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 } from \"react\";\nimport { useEffect, useState } from \"react\";\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 {\n readonly stamp: SpotItem;\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?: SupportedLocale;\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({\n stamp,\n record,\n isNext = false,\n slotNumber = 1,\n presentation = {},\n isAnimating = false,\n disabled = false,\n slotShape = \"rounded\",\n locale = \"ja\",\n statusText,\n onSelect,\n}: StampSlotProps) {\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 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 {\n readonly title?: LocalizedText;\n readonly config: RallyConfig;\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?: SupportedLocale;\n readonly theme?: SheetTheme;\n readonly onStampSelect?: (stampId: string) => void;\n}\n\nexport function StampSheet({\n title,\n config,\n state = null,\n progress,\n presentations = {},\n animatedStampId = null,\n disabled = false,\n locale = \"ja\",\n theme = config.theme ?? DEFAULT_SHEET_THEME,\n onStampSelect,\n}: StampSheetProps) {\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 locale === \"en\"\n ? {\n available: \"available\",\n locked: \"locked\",\n stamped: \"stamped\",\n remaining: (value: number) => `${value} spots remaining`,\n completed: \"RALLY COMPLETED\",\n }\n : {\n available: \"取得可能\",\n locked: \"順序待ち\",\n stamped: \"取得済み\",\n remaining: (value: number) => `あと${value}箇所`,\n 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\" 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 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 && <div className=\"stamp-sheet__complete-mark\">COMPLETE!!</div>}\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 {\n readonly open: boolean;\n readonly stamp: SpotItem | 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?: SupportedLocale;\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({\n open,\n stamp,\n record,\n isAvailable = true,\n isPending = false,\n locale = \"ja\",\n onClose,\n onAcquire,\n onCheckIn,\n onNotify,\n}: StampModalProps) {\n const [token, setToken] = useState(\"\");\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 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\">\n <button type=\"button\" aria-label=\"Close\" onClick={onClose} disabled={isPending}>\n ×\n </button>\n <h2 id=\"stamprally-modal-title\">{name}</h2>\n {record !== undefined ? (\n <p>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 Passcode <input value={token} onChange={(event) => setToken(event.target.value)} />\n </label>\n <button type=\"submit\" disabled={!isAvailable || isPending}>\n Claim stamp\n </button>\n </form>\n ) : (\n <button\n type=\"button\"\n onClick={() => void submit({ type: \"instant\" })}\n disabled={!isAvailable || isPending}\n >\n Claim stamp\n </button>\n )}\n </div>\n </div>\n );\n}\n\nexport interface RewardPanelProps {\n readonly rewards: ReadonlyArray<RewardItem>;\n readonly states: ReadonlyArray<RewardState>;\n readonly locale?: SupportedLocale;\n readonly isPending?: boolean;\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({\n rewards,\n states,\n locale = \"ja\",\n isPending = false,\n onRedeem,\n onNotify,\n}: RewardPanelProps) {\n const [passcodes, setPasscodes] = useState<Readonly<Record<string, string>>>({});\n return (\n <section aria-labelledby=\"stamprally-rewards-title\" className=\"stamprally-rewards\">\n <h2 id=\"stamprally-rewards-title\">Rewards</h2>\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?.(result.ok, result.ok ? \"Reward claimed.\" : result.error.code);\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>{state?.status ?? \"LOCKED\"}</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 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 type=\"submit\" disabled={!available || isPending}>\n Redeem\n </button>\n </form>\n )}\n {reward.redemptionMethod !== \"staff_passcode\" && (\n <button\n type=\"button\"\n disabled={!available || isPending}\n onClick={() => void redeem()}\n >\n Redeem\n </button>\n )}\n </article>\n );\n })}\n </section>\n );\n}\n"]}
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
.stamp-sheet,
|
|
2
|
+
:where(.stamprally-sheet, .stamprally-rewards) {
|
|
3
|
+
color: var(--stamprally-text, #352f25);
|
|
4
|
+
background: var(--stamprally-background, transparent);
|
|
5
|
+
}
|
|
6
|
+
.stamp-sheet {
|
|
7
|
+
display: grid;
|
|
8
|
+
gap: 1rem;
|
|
9
|
+
padding: 1.5rem;
|
|
10
|
+
border: 1px solid color-mix(in srgb, var(--stamp-primary, #9e551e) 35%, #fff);
|
|
11
|
+
border-radius: 1.5rem;
|
|
12
|
+
color: var(--stamp-text, #352f25);
|
|
13
|
+
font-family: var(--stamp-font-family, Georgia, "Times New Roman", serif);
|
|
14
|
+
background: var(--stamp-bg, #fbf4df);
|
|
15
|
+
}
|
|
16
|
+
.stamp-sheet__header,
|
|
17
|
+
.stamp-sheet__progress-label,
|
|
18
|
+
.stamp-slot__topline {
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: baseline;
|
|
21
|
+
justify-content: space-between;
|
|
22
|
+
gap: 1rem;
|
|
23
|
+
}
|
|
24
|
+
.stamp-sheet__header h2 {
|
|
25
|
+
margin: 0;
|
|
26
|
+
}
|
|
27
|
+
.stamp-sheet__progress-label {
|
|
28
|
+
font-size: 0.85rem;
|
|
29
|
+
}
|
|
30
|
+
.stamp-sheet__progress-track {
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
height: 0.5rem;
|
|
33
|
+
border-radius: 999px;
|
|
34
|
+
background: color-mix(in srgb, var(--stamp-primary, #9e551e) 15%, #fff);
|
|
35
|
+
}
|
|
36
|
+
.stamp-sheet__progress-fill {
|
|
37
|
+
height: 100%;
|
|
38
|
+
border-radius: inherit;
|
|
39
|
+
background: var(--stamp-primary, #9e551e);
|
|
40
|
+
}
|
|
41
|
+
.stamp-sheet__grid {
|
|
42
|
+
display: grid;
|
|
43
|
+
grid-template-columns: repeat(var(--stamp-grid-cols, 3), minmax(0, 1fr));
|
|
44
|
+
gap: 1rem;
|
|
45
|
+
}
|
|
46
|
+
.stamp-slot {
|
|
47
|
+
position: relative;
|
|
48
|
+
color: var(--stamprally-text, #352f25);
|
|
49
|
+
display: grid;
|
|
50
|
+
gap: 0.35rem;
|
|
51
|
+
min-height: 10rem;
|
|
52
|
+
padding: 1rem;
|
|
53
|
+
background: var(--stamprally-card, #fff);
|
|
54
|
+
border: 2px solid var(--stamprally-primary, #9e551e);
|
|
55
|
+
cursor: pointer;
|
|
56
|
+
}
|
|
57
|
+
.stamp-slot__number,
|
|
58
|
+
.stamp-slot__state,
|
|
59
|
+
.stamp-slot__condition {
|
|
60
|
+
font-size: 0.72rem;
|
|
61
|
+
font-weight: 700;
|
|
62
|
+
}
|
|
63
|
+
.stamp-slot__watermark {
|
|
64
|
+
font-size: 2rem;
|
|
65
|
+
opacity: 0.35;
|
|
66
|
+
}
|
|
67
|
+
.stamp-slot__name {
|
|
68
|
+
font-weight: 800;
|
|
69
|
+
}
|
|
70
|
+
.stamp-slot__condition {
|
|
71
|
+
opacity: 0.75;
|
|
72
|
+
}
|
|
73
|
+
.stamp-imprint {
|
|
74
|
+
display: grid;
|
|
75
|
+
place-items: center;
|
|
76
|
+
padding: 0.35rem;
|
|
77
|
+
border: 2px solid var(--stamp-completed-color, #b33c2e);
|
|
78
|
+
color: var(--stamp-completed-color, #b33c2e);
|
|
79
|
+
transform: rotate(-4deg);
|
|
80
|
+
}
|
|
81
|
+
.stamp-imprint__inner {
|
|
82
|
+
display: grid;
|
|
83
|
+
gap: 0.1rem;
|
|
84
|
+
text-align: center;
|
|
85
|
+
}
|
|
86
|
+
.stamp-slot--locked {
|
|
87
|
+
opacity: var(--stamp-unclaimed-opacity, 0.55);
|
|
88
|
+
cursor: not-allowed;
|
|
89
|
+
}
|
|
90
|
+
.stamp-slot--animating {
|
|
91
|
+
animation: stamprally-stamp-press 0.5s ease-out;
|
|
92
|
+
}
|
|
93
|
+
.stamprally-modal {
|
|
94
|
+
position: fixed;
|
|
95
|
+
inset: 0;
|
|
96
|
+
display: grid;
|
|
97
|
+
place-items: center;
|
|
98
|
+
padding: 1rem;
|
|
99
|
+
background: #0008;
|
|
100
|
+
}
|
|
101
|
+
.stamprally-modal__panel {
|
|
102
|
+
max-width: 32rem;
|
|
103
|
+
width: 100%;
|
|
104
|
+
padding: 1.5rem;
|
|
105
|
+
background: var(--stamprally-card, #fff);
|
|
106
|
+
}
|
|
107
|
+
@keyframes stamprally-stamp-press {
|
|
108
|
+
50% {
|
|
109
|
+
transform: scale(0.96) rotate(-2deg);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
@media (max-width: 640px) {
|
|
113
|
+
.stamp-sheet__grid {
|
|
114
|
+
grid-template-columns: repeat(var(--stamp-grid-cols-mobile, 2), minmax(0, 1fr));
|
|
115
|
+
}
|
|
116
|
+
}
|
package/dist/index.d.cts
CHANGED
|
@@ -5,6 +5,7 @@ interface StampPresentation {
|
|
|
5
5
|
readonly label?: string;
|
|
6
6
|
readonly icon?: string;
|
|
7
7
|
readonly ink?: "vermilion" | "indigo";
|
|
8
|
+
readonly channel?: "instant" | "qr" | "nfc" | "geo";
|
|
8
9
|
}
|
|
9
10
|
interface StampSlotProps {
|
|
10
11
|
readonly stamp: SpotItem;
|
|
@@ -16,9 +17,10 @@ interface StampSlotProps {
|
|
|
16
17
|
readonly disabled?: boolean;
|
|
17
18
|
readonly slotShape?: SlotShape;
|
|
18
19
|
readonly locale?: SupportedLocale;
|
|
20
|
+
readonly statusText?: string;
|
|
19
21
|
readonly onSelect?: () => void;
|
|
20
22
|
}
|
|
21
|
-
declare function StampSlot({ stamp, record, isNext, slotNumber, presentation, isAnimating, disabled, slotShape, locale, onSelect, }: StampSlotProps): react.JSX.Element;
|
|
23
|
+
declare function StampSlot({ stamp, record, isNext, slotNumber, presentation, isAnimating, disabled, slotShape, locale, statusText, onSelect, }: StampSlotProps): react.JSX.Element;
|
|
22
24
|
interface StampSheetProps {
|
|
23
25
|
readonly title?: LocalizedText;
|
|
24
26
|
readonly config: RallyConfig;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ interface StampPresentation {
|
|
|
5
5
|
readonly label?: string;
|
|
6
6
|
readonly icon?: string;
|
|
7
7
|
readonly ink?: "vermilion" | "indigo";
|
|
8
|
+
readonly channel?: "instant" | "qr" | "nfc" | "geo";
|
|
8
9
|
}
|
|
9
10
|
interface StampSlotProps {
|
|
10
11
|
readonly stamp: SpotItem;
|
|
@@ -16,9 +17,10 @@ interface StampSlotProps {
|
|
|
16
17
|
readonly disabled?: boolean;
|
|
17
18
|
readonly slotShape?: SlotShape;
|
|
18
19
|
readonly locale?: SupportedLocale;
|
|
20
|
+
readonly statusText?: string;
|
|
19
21
|
readonly onSelect?: () => void;
|
|
20
22
|
}
|
|
21
|
-
declare function StampSlot({ stamp, record, isNext, slotNumber, presentation, isAnimating, disabled, slotShape, locale, onSelect, }: StampSlotProps): react.JSX.Element;
|
|
23
|
+
declare function StampSlot({ stamp, record, isNext, slotNumber, presentation, isAnimating, disabled, slotShape, locale, statusText, onSelect, }: StampSlotProps): react.JSX.Element;
|
|
22
24
|
interface StampSheetProps {
|
|
23
25
|
readonly title?: LocalizedText;
|
|
24
26
|
readonly config: RallyConfig;
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,19 @@ import { useState, useEffect } from 'react';
|
|
|
3
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
4
|
|
|
5
5
|
// src/index.tsx
|
|
6
|
+
var FONT_STACKS = {
|
|
7
|
+
"system-ui": 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
8
|
+
serif: 'Georgia, "Times New Roman", "Yu Mincho", serif',
|
|
9
|
+
"rounded-sans": '"Arial Rounded MT Bold", "Hiragino Maru Gothic ProN", "Yu Gothic", sans-serif',
|
|
10
|
+
monospace: 'ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace',
|
|
11
|
+
handwritten: '"Segoe Print", "Bradley Hand", "Comic Sans MS", cursive'
|
|
12
|
+
};
|
|
13
|
+
function formatStampDate(value) {
|
|
14
|
+
const date = new Date(value);
|
|
15
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
16
|
+
const pad = (part) => String(part).padStart(2, "0");
|
|
17
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
18
|
+
}
|
|
6
19
|
function StampSlot({
|
|
7
20
|
stamp,
|
|
8
21
|
record,
|
|
@@ -13,9 +26,12 @@ function StampSlot({
|
|
|
13
26
|
disabled = false,
|
|
14
27
|
slotShape = "rounded",
|
|
15
28
|
locale = "ja",
|
|
29
|
+
statusText,
|
|
16
30
|
onSelect
|
|
17
31
|
}) {
|
|
18
32
|
const status = record === void 0 ? isNext ? "available" : "locked" : "stamped";
|
|
33
|
+
const resolvedStatus = statusText ?? status;
|
|
34
|
+
const statusSeparator = statusText !== void 0 && locale === "ja" ? "\u3001" : ", ";
|
|
19
35
|
const name = resolveLocalizedText(stamp.name, locale);
|
|
20
36
|
const label = presentation.label ?? stamp.condition.type;
|
|
21
37
|
return /* @__PURE__ */ jsxs(
|
|
@@ -24,16 +40,37 @@ function StampSlot({
|
|
|
24
40
|
type: "button",
|
|
25
41
|
disabled,
|
|
26
42
|
onClick: onSelect,
|
|
27
|
-
"aria-label":
|
|
43
|
+
"aria-label": `#${String(slotNumber).padStart(2, "0")} ${name}${statusSeparator}${resolvedStatus}`,
|
|
28
44
|
"data-status": status,
|
|
29
45
|
"data-shape": slotShape,
|
|
30
|
-
className: `stamp-slot stamp-slot--${status}${isAnimating ? " stamp-slot--animating" : ""}`,
|
|
46
|
+
className: `stamp-slot stamp-slot--${status} stamp-slot--${presentation.ink ?? "vermilion"} stamp-slot--shape-${slotShape}${isAnimating ? " stamp-slot--animating" : ""}`,
|
|
31
47
|
style: { "--stamp-primary": "var(--stamprally-primary, #9e551e)" },
|
|
32
48
|
children: [
|
|
33
|
-
/* @__PURE__ */
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
49
|
+
/* @__PURE__ */ jsxs("span", { className: "stamp-slot__topline", children: [
|
|
50
|
+
/* @__PURE__ */ jsxs("span", { className: "stamp-slot__number", children: [
|
|
51
|
+
"#",
|
|
52
|
+
String(slotNumber).padStart(2, "0")
|
|
53
|
+
] }),
|
|
54
|
+
/* @__PURE__ */ jsx("span", { className: `stamp-slot__state stamp-slot__state--${status}`, children: resolvedStatus })
|
|
55
|
+
] }),
|
|
56
|
+
/* @__PURE__ */ jsx("span", { className: "stamp-slot__watermark", "aria-hidden": "true", children: presentation.icon ?? "\u2726" }),
|
|
57
|
+
/* @__PURE__ */ jsx("span", { className: "stamp-slot__name", children: name }),
|
|
58
|
+
/* @__PURE__ */ jsxs("span", { className: "stamp-slot__condition", children: [
|
|
59
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: presentation.icon ?? "\u2726" }),
|
|
60
|
+
label
|
|
61
|
+
] }),
|
|
62
|
+
record !== void 0 && /* @__PURE__ */ jsx(
|
|
63
|
+
"span",
|
|
64
|
+
{
|
|
65
|
+
className: `stamp-imprint ${isAnimating ? "stamp-press" : ""}`,
|
|
66
|
+
role: "img",
|
|
67
|
+
"aria-label": `Acquired at ${formatStampDate(record.acquiredAt)}`,
|
|
68
|
+
children: /* @__PURE__ */ jsxs("span", { className: "stamp-imprint__inner", children: [
|
|
69
|
+
/* @__PURE__ */ jsx("span", { className: "stamp-imprint__word", children: "STAMP" }),
|
|
70
|
+
/* @__PURE__ */ jsx("span", { className: "stamp-imprint__date", children: formatStampDate(record.acquiredAt) })
|
|
71
|
+
] })
|
|
72
|
+
}
|
|
73
|
+
)
|
|
37
74
|
]
|
|
38
75
|
}
|
|
39
76
|
);
|
|
@@ -56,54 +93,96 @@ function StampSheet({
|
|
|
56
93
|
const total = progress?.total ?? config.stamps.length;
|
|
57
94
|
const percentage = progress?.percentage ?? (total === 0 ? 0 : count / total * 100);
|
|
58
95
|
const style = {
|
|
59
|
-
"--
|
|
60
|
-
"--
|
|
61
|
-
"--
|
|
62
|
-
"--
|
|
96
|
+
"--stamp-primary": `var(--stamprally-primary-override, ${theme.primaryColor})`,
|
|
97
|
+
"--stamp-bg": `var(--stamprally-background-override, ${theme.backgroundColor ?? DEFAULT_SHEET_THEME.backgroundColor ?? "#ffffff"})`,
|
|
98
|
+
"--stamp-card-bg": `var(--stamprally-card-override, ${theme.cardBackgroundColor})`,
|
|
99
|
+
"--stamp-text": `var(--stamprally-text-override, ${theme.textColor})`,
|
|
100
|
+
"--stamp-grid-cols": String(theme.gridColumns),
|
|
101
|
+
"--stamp-grid-cols-mobile": String(Math.min(theme.gridColumns, 2)),
|
|
102
|
+
"--stamp-unclaimed-opacity": String(theme.unclaimedOpacity ?? 1),
|
|
103
|
+
"--stamp-font-family": FONT_STACKS[theme.fontFamily ?? "serif"],
|
|
104
|
+
...theme.completedStampColor === void 0 ? {} : { "--stamp-completed-color": theme.completedStampColor },
|
|
105
|
+
"--stamprally-primary": `var(--stamprally-primary-override, ${theme.primaryColor})`,
|
|
106
|
+
"--stamprally-background": `var(--stamprally-background-override, ${theme.backgroundColor ?? "transparent"})`,
|
|
107
|
+
"--stamprally-card": `var(--stamprally-card-override, ${theme.cardBackgroundColor})`,
|
|
108
|
+
"--stamprally-text": `var(--stamprally-text-override, ${theme.textColor})`,
|
|
63
109
|
"--stamprally-columns": String(theme.gridColumns)
|
|
64
110
|
};
|
|
111
|
+
const messages = locale === "en" ? {
|
|
112
|
+
available: "available",
|
|
113
|
+
locked: "locked",
|
|
114
|
+
stamped: "stamped",
|
|
115
|
+
remaining: (value) => `${value} spots remaining`,
|
|
116
|
+
completed: "RALLY COMPLETED"
|
|
117
|
+
} : {
|
|
118
|
+
available: "\u53D6\u5F97\u53EF\u80FD",
|
|
119
|
+
locked: "\u9806\u5E8F\u5F85\u3061",
|
|
120
|
+
stamped: "\u53D6\u5F97\u6E08\u307F",
|
|
121
|
+
remaining: (value) => `\u3042\u3068${value}\u7B87\u6240`,
|
|
122
|
+
completed: "\u30E9\u30EA\u30FC\u9054\u6210"
|
|
123
|
+
};
|
|
65
124
|
return /* @__PURE__ */ jsxs(
|
|
66
125
|
"section",
|
|
67
126
|
{
|
|
68
|
-
className: "
|
|
127
|
+
className: `stamp-sheet ${percentage >= 100 ? "stamp-sheet--completed" : ""}`,
|
|
69
128
|
style,
|
|
70
129
|
"aria-label": resolveLocalizedText(title, locale) || config.id,
|
|
71
130
|
children: [
|
|
72
|
-
/* @__PURE__ */ jsxs("header", { children: [
|
|
131
|
+
/* @__PURE__ */ jsxs("header", { className: "stamp-sheet__header", children: [
|
|
73
132
|
/* @__PURE__ */ jsx("h2", { children: resolveLocalizedText(title, locale) || config.id }),
|
|
74
|
-
/* @__PURE__ */ jsxs("span", { "aria-live": "polite", children: [
|
|
133
|
+
/* @__PURE__ */ jsxs("span", { className: "stamp-sheet__score", "aria-live": "polite", children: [
|
|
75
134
|
count,
|
|
76
135
|
" / ",
|
|
77
136
|
total
|
|
78
137
|
] })
|
|
79
138
|
] }),
|
|
139
|
+
/* @__PURE__ */ jsxs("div", { className: "stamp-sheet__progress-label", children: [
|
|
140
|
+
/* @__PURE__ */ jsx("span", { children: messages.remaining(Math.max(0, total - count)) }),
|
|
141
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
142
|
+
Math.round(percentage),
|
|
143
|
+
"%"
|
|
144
|
+
] })
|
|
145
|
+
] }),
|
|
80
146
|
/* @__PURE__ */ jsx(
|
|
81
147
|
"div",
|
|
82
148
|
{
|
|
149
|
+
className: "stamp-sheet__progress-track",
|
|
83
150
|
role: "progressbar",
|
|
84
151
|
"aria-valuemin": 0,
|
|
85
152
|
"aria-valuemax": 100,
|
|
86
153
|
"aria-valuenow": Math.round(percentage),
|
|
87
|
-
"aria-label": "Rally progress",
|
|
88
|
-
children: /* @__PURE__ */ jsx(
|
|
154
|
+
"aria-label": locale === "en" ? "Rally progress" : "\u30B9\u30BF\u30F3\u30D7\u53D6\u5F97\u9032\u6357",
|
|
155
|
+
children: /* @__PURE__ */ jsx(
|
|
156
|
+
"span",
|
|
157
|
+
{
|
|
158
|
+
className: "stamp-sheet__progress-fill",
|
|
159
|
+
style: { display: "block", width: `${percentage}%` }
|
|
160
|
+
}
|
|
161
|
+
)
|
|
89
162
|
}
|
|
90
163
|
),
|
|
91
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
164
|
+
/* @__PURE__ */ jsx("div", { className: "stamp-sheet__grid", children: config.stamps.map((stamp, index) => {
|
|
165
|
+
const recordForStamp = state?.records.find((record) => record.stampId === stamp.id);
|
|
166
|
+
return /* @__PURE__ */ jsx(
|
|
167
|
+
StampSlot,
|
|
168
|
+
{
|
|
169
|
+
stamp,
|
|
170
|
+
...recordForStamp === void 0 ? {} : { record: recordForStamp },
|
|
171
|
+
isNext: next.has(stamp.id),
|
|
172
|
+
slotNumber: index + 1,
|
|
173
|
+
...presentations[stamp.id] === void 0 ? {} : { presentation: presentations[stamp.id] },
|
|
174
|
+
isAnimating: animatedStampId === stamp.id,
|
|
175
|
+
disabled,
|
|
176
|
+
slotShape: theme.slotShape,
|
|
177
|
+
locale,
|
|
178
|
+
statusText: recordForStamp === void 0 ? next.has(stamp.id) ? messages.available : messages.locked : messages.stamped,
|
|
179
|
+
onSelect: () => onStampSelect?.(stamp.id)
|
|
180
|
+
},
|
|
181
|
+
stamp.id
|
|
182
|
+
);
|
|
183
|
+
}) }),
|
|
184
|
+
percentage >= 100 && /* @__PURE__ */ jsx("div", { className: "stamp-sheet__complete-mark", children: "COMPLETE!!" }),
|
|
185
|
+
percentage >= 100 && /* @__PURE__ */ jsx("div", { className: "stamp-sheet__complete-message", children: messages.completed })
|
|
107
186
|
]
|
|
108
187
|
}
|
|
109
188
|
);
|
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 LocalizedText,\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 } from \"react\";\nimport { useEffect, useState } from \"react\";\n\nexport interface StampPresentation {\n readonly label?: string;\n readonly icon?: string;\n readonly ink?: \"vermilion\" | \"indigo\";\n}\n\nexport interface StampSlotProps {\n readonly stamp: SpotItem;\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?: SupportedLocale;\n readonly onSelect?: () => void;\n}\n\nexport function StampSlot({\n stamp,\n record,\n isNext = false,\n slotNumber = 1,\n presentation = {},\n isAnimating = false,\n disabled = false,\n slotShape = \"rounded\",\n locale = \"ja\",\n onSelect,\n}: StampSlotProps) {\n const status = record === undefined ? (isNext ? \"available\" : \"locked\") : \"stamped\";\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={`${slotNumber}. ${name} (${status})`}\n data-status={status}\n data-shape={slotShape}\n className={`stamp-slot stamp-slot--${status}${isAnimating ? \" stamp-slot--animating\" : \"\"}`}\n style={{ \"--stamp-primary\": \"var(--stamprally-primary, #9e551e)\" } as CSSProperties}\n >\n <span aria-hidden=\"true\">{presentation.icon ?? \"✦\"}</span>\n <strong>{name}</strong>\n <small>{label}</small>\n {record !== undefined && <time dateTime={record.acquiredAt}>{record.acquiredAt}</time>}\n </button>\n );\n}\n\nexport interface StampSheetProps {\n readonly title?: LocalizedText;\n readonly config: RallyConfig;\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?: SupportedLocale;\n readonly theme?: SheetTheme;\n readonly onStampSelect?: (stampId: string) => void;\n}\n\nexport function StampSheet({\n title,\n config,\n state = null,\n progress,\n presentations = {},\n animatedStampId = null,\n disabled = false,\n locale = \"ja\",\n theme = config.theme ?? DEFAULT_SHEET_THEME,\n onStampSelect,\n}: StampSheetProps) {\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 \"--stamprally-primary\": theme.primaryColor,\n \"--stamprally-background\": theme.backgroundColor ?? \"transparent\",\n \"--stamprally-card\": theme.cardBackgroundColor,\n \"--stamprally-text\": theme.textColor,\n \"--stamprally-columns\": String(theme.gridColumns),\n } as CSSProperties;\n return (\n <section\n className=\"stamprally-sheet\"\n style={style}\n aria-label={resolveLocalizedText(title, locale) || config.id}\n >\n <header>\n <h2>{resolveLocalizedText(title, locale) || config.id}</h2>\n <span aria-live=\"polite\">\n {count} / {total}\n </span>\n </header>\n <div\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(percentage)}\n aria-label=\"Rally progress\"\n >\n <span style={{ display: \"block\", width: `${percentage}%` }} />\n </div>\n <div className=\"stamprally-sheet__grid\">\n {config.stamps.map((stamp, index) => (\n <StampSlot\n key={stamp.id}\n stamp={stamp}\n {...(state?.records.find((record) => record.stampId === stamp.id) === undefined\n ? {}\n : { record: state?.records.find((record) => record.stampId === stamp.id) })}\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 onSelect={() => onStampSelect?.(stamp.id)}\n />\n ))}\n </div>\n </section>\n );\n}\n\nexport interface AcquisitionFeedback {\n readonly ok: boolean;\n readonly message: string;\n}\nexport interface StampModalProps {\n readonly open: boolean;\n readonly stamp: SpotItem | 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?: SupportedLocale;\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({\n open,\n stamp,\n record,\n isAvailable = true,\n isPending = false,\n locale = \"ja\",\n onClose,\n onAcquire,\n onCheckIn,\n onNotify,\n}: StampModalProps) {\n const [token, setToken] = useState(\"\");\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 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\">\n <button type=\"button\" aria-label=\"Close\" onClick={onClose} disabled={isPending}>\n ×\n </button>\n <h2 id=\"stamprally-modal-title\">{name}</h2>\n {record !== undefined ? (\n <p>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 Passcode <input value={token} onChange={(event) => setToken(event.target.value)} />\n </label>\n <button type=\"submit\" disabled={!isAvailable || isPending}>\n Claim stamp\n </button>\n </form>\n ) : (\n <button\n type=\"button\"\n onClick={() => void submit({ type: \"instant\" })}\n disabled={!isAvailable || isPending}\n >\n Claim stamp\n </button>\n )}\n </div>\n </div>\n );\n}\n\nexport interface RewardPanelProps {\n readonly rewards: ReadonlyArray<RewardItem>;\n readonly states: ReadonlyArray<RewardState>;\n readonly locale?: SupportedLocale;\n readonly isPending?: boolean;\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({\n rewards,\n states,\n locale = \"ja\",\n isPending = false,\n onRedeem,\n onNotify,\n}: RewardPanelProps) {\n const [passcodes, setPasscodes] = useState<Readonly<Record<string, string>>>({});\n return (\n <section aria-labelledby=\"stamprally-rewards-title\" className=\"stamprally-rewards\">\n <h2 id=\"stamprally-rewards-title\">Rewards</h2>\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?.(result.ok, result.ok ? \"Reward claimed.\" : result.error.code);\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>{state?.status ?? \"LOCKED\"}</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 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 type=\"submit\" disabled={!available || isPending}>\n Redeem\n </button>\n </form>\n )}\n {reward.redemptionMethod !== \"staff_passcode\" && (\n <button\n type=\"button\"\n disabled={!available || isPending}\n onClick={() => void redeem()}\n >\n 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 ConsumeResult,\n DEFAULT_SHEET_THEME,\n type LocalizedText,\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 } from \"react\";\nimport { useEffect, useState } from \"react\";\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 {\n readonly stamp: SpotItem;\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?: SupportedLocale;\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({\n stamp,\n record,\n isNext = false,\n slotNumber = 1,\n presentation = {},\n isAnimating = false,\n disabled = false,\n slotShape = \"rounded\",\n locale = \"ja\",\n statusText,\n onSelect,\n}: StampSlotProps) {\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 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 {\n readonly title?: LocalizedText;\n readonly config: RallyConfig;\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?: SupportedLocale;\n readonly theme?: SheetTheme;\n readonly onStampSelect?: (stampId: string) => void;\n}\n\nexport function StampSheet({\n title,\n config,\n state = null,\n progress,\n presentations = {},\n animatedStampId = null,\n disabled = false,\n locale = \"ja\",\n theme = config.theme ?? DEFAULT_SHEET_THEME,\n onStampSelect,\n}: StampSheetProps) {\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 locale === \"en\"\n ? {\n available: \"available\",\n locked: \"locked\",\n stamped: \"stamped\",\n remaining: (value: number) => `${value} spots remaining`,\n completed: \"RALLY COMPLETED\",\n }\n : {\n available: \"取得可能\",\n locked: \"順序待ち\",\n stamped: \"取得済み\",\n remaining: (value: number) => `あと${value}箇所`,\n 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\" 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 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 && <div className=\"stamp-sheet__complete-mark\">COMPLETE!!</div>}\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 {\n readonly open: boolean;\n readonly stamp: SpotItem | 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?: SupportedLocale;\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({\n open,\n stamp,\n record,\n isAvailable = true,\n isPending = false,\n locale = \"ja\",\n onClose,\n onAcquire,\n onCheckIn,\n onNotify,\n}: StampModalProps) {\n const [token, setToken] = useState(\"\");\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 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\">\n <button type=\"button\" aria-label=\"Close\" onClick={onClose} disabled={isPending}>\n ×\n </button>\n <h2 id=\"stamprally-modal-title\">{name}</h2>\n {record !== undefined ? (\n <p>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 Passcode <input value={token} onChange={(event) => setToken(event.target.value)} />\n </label>\n <button type=\"submit\" disabled={!isAvailable || isPending}>\n Claim stamp\n </button>\n </form>\n ) : (\n <button\n type=\"button\"\n onClick={() => void submit({ type: \"instant\" })}\n disabled={!isAvailable || isPending}\n >\n Claim stamp\n </button>\n )}\n </div>\n </div>\n );\n}\n\nexport interface RewardPanelProps {\n readonly rewards: ReadonlyArray<RewardItem>;\n readonly states: ReadonlyArray<RewardState>;\n readonly locale?: SupportedLocale;\n readonly isPending?: boolean;\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({\n rewards,\n states,\n locale = \"ja\",\n isPending = false,\n onRedeem,\n onNotify,\n}: RewardPanelProps) {\n const [passcodes, setPasscodes] = useState<Readonly<Record<string, string>>>({});\n return (\n <section aria-labelledby=\"stamprally-rewards-title\" className=\"stamprally-rewards\">\n <h2 id=\"stamprally-rewards-title\">Rewards</h2>\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?.(result.ok, result.ok ? \"Reward claimed.\" : result.error.code);\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>{state?.status ?? \"LOCKED\"}</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 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 type=\"submit\" disabled={!available || isPending}>\n Redeem\n </button>\n </form>\n )}\n {reward.redemptionMethod !== \"staff_passcode\" && (\n <button\n type=\"button\"\n disabled={!available || isPending}\n onClick={() => void redeem()}\n >\n 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.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Accessible participant UI components for stamp rallies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
"type": "module",
|
|
16
16
|
"sideEffects": false,
|
|
17
17
|
"files": [
|
|
18
|
-
"dist"
|
|
19
|
-
"src/styles.css"
|
|
18
|
+
"dist"
|
|
20
19
|
],
|
|
21
20
|
"main": "./dist/index.cjs",
|
|
22
21
|
"module": "./dist/index.js",
|
|
@@ -27,11 +26,11 @@
|
|
|
27
26
|
"import": "./dist/index.js",
|
|
28
27
|
"require": "./dist/index.cjs"
|
|
29
28
|
},
|
|
30
|
-
"./styles.css": "./
|
|
29
|
+
"./styles.css": "./dist/index.css"
|
|
31
30
|
},
|
|
32
31
|
"dependencies": {
|
|
33
|
-
"@stamprally/
|
|
34
|
-
"@stamprally/
|
|
32
|
+
"@stamprally/react": "0.3.0",
|
|
33
|
+
"@stamprally/core": "0.3.0"
|
|
35
34
|
},
|
|
36
35
|
"peerDependencies": {
|
|
37
36
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -48,7 +47,7 @@
|
|
|
48
47
|
"vitest": "^4.1.11"
|
|
49
48
|
},
|
|
50
49
|
"scripts": {
|
|
51
|
-
"build": "tsup",
|
|
50
|
+
"build": "tsup && node ../../scripts/copy-package-css.mjs packages/ui",
|
|
52
51
|
"dev": "tsup --watch",
|
|
53
52
|
"test": "vitest run",
|
|
54
53
|
"typecheck": "tsc -p tsconfig.json"
|
package/src/styles.css
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
:where(.stamprally-sheet, .stamprally-rewards) {
|
|
2
|
-
color: var(--stamprally-text, #352f25);
|
|
3
|
-
background: var(--stamprally-background, transparent);
|
|
4
|
-
}
|
|
5
|
-
.stamprally-sheet__grid {
|
|
6
|
-
display: grid;
|
|
7
|
-
grid-template-columns: repeat(var(--stamprally-columns, 3), minmax(0, 1fr));
|
|
8
|
-
gap: 1rem;
|
|
9
|
-
}
|
|
10
|
-
.stamp-slot {
|
|
11
|
-
display: grid;
|
|
12
|
-
gap: 0.35rem;
|
|
13
|
-
min-height: 8rem;
|
|
14
|
-
padding: 1rem;
|
|
15
|
-
color: var(--stamprally-text, #352f25);
|
|
16
|
-
background: var(--stamprally-card, #fff);
|
|
17
|
-
border: 2px solid var(--stamprally-primary, #9e551e);
|
|
18
|
-
cursor: pointer;
|
|
19
|
-
}
|
|
20
|
-
.stamp-slot--locked {
|
|
21
|
-
opacity: 0.55;
|
|
22
|
-
cursor: not-allowed;
|
|
23
|
-
}
|
|
24
|
-
.stamp-slot--animating {
|
|
25
|
-
animation: stamprally-stamp-press 0.5s ease-out;
|
|
26
|
-
}
|
|
27
|
-
.stamprally-modal {
|
|
28
|
-
position: fixed;
|
|
29
|
-
inset: 0;
|
|
30
|
-
display: grid;
|
|
31
|
-
place-items: center;
|
|
32
|
-
padding: 1rem;
|
|
33
|
-
background: #0008;
|
|
34
|
-
}
|
|
35
|
-
.stamprally-modal__panel {
|
|
36
|
-
max-width: 32rem;
|
|
37
|
-
width: 100%;
|
|
38
|
-
padding: 1.5rem;
|
|
39
|
-
background: var(--stamprally-card, #fff);
|
|
40
|
-
}
|
|
41
|
-
@keyframes stamprally-stamp-press {
|
|
42
|
-
50% {
|
|
43
|
-
transform: scale(0.96) rotate(-2deg);
|
|
44
|
-
}
|
|
45
|
-
}
|