@eintrek/erp-shell 0.1.72 → 0.1.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/chunks/{guide-runtime-B-3myqxe.esm.js → guide-runtime-Dl8V1iy9.esm.js} +963 -52
- package/dist/chunks/guide-runtime-Dl8V1iy9.esm.js.map +1 -0
- package/dist/chunks/{guide-runtime-DfnNdrjZ.cjs → guide-runtime-YS2nUhwS.cjs} +967 -50
- package/dist/chunks/guide-runtime-YS2nUhwS.cjs.map +1 -0
- package/dist/guide/core.d.ts +3 -3
- package/dist/guide/guide-store.d.ts +41 -0
- package/dist/guide/guide-styles.d.ts +1 -1
- package/dist/guide/guide-ui.d.ts +40 -0
- package/dist/guide/machine.d.ts +118 -2
- package/dist/guide/pages.d.ts +56 -0
- package/dist/guide/progress-sync.d.ts +9 -1
- package/dist/guide/progress.d.ts +25 -0
- package/dist/guide/types.d.ts +72 -0
- package/dist/guide-core.cjs +7 -1
- package/dist/guide-core.cjs.map +1 -1
- package/dist/guide-core.esm.js +1 -1
- package/dist/help/help-button.d.ts +5 -3
- package/dist/index.cjs +22 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.esm.js +19 -13
- package/dist/index.esm.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunks/guide-runtime-B-3myqxe.esm.js.map +0 -1
- package/dist/chunks/guide-runtime-DfnNdrjZ.cjs.map +0 -1
package/dist/guide/core.d.ts
CHANGED
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
* The main entry re-exports the same modules, so a tour defined against
|
|
11
11
|
* either entry is the same data, and the bus and the "?" entry are shared.
|
|
12
12
|
*/
|
|
13
|
-
export type { GuideAbortAction, GuideAnchorKey, GuideApiFailure, GuideApiMatch, GuideAppId, GuideCaptureEvent, GuideConfig, GuideContext, GuideFacts, GuideGate, GuideMission, GuideNothingToSave, GuideOnMissing, GuideStep, GuideStepKind, GuideSuite, GuideText, GuideTrigger, } from "./types";
|
|
13
|
+
export type { GuideAbortAction, GuideAnchorKey, GuideApiFailure, GuideApiMatch, GuideAppId, GuideCaptureEvent, GuideConfig, GuideContext, GuideFacts, GuideGate, GuideMission, GuideNothingToSave, GuideOnMissing, GuidePage, GuideStep, GuideStepKind, GuideSuite, GuideText, GuideTrigger, } from "./types";
|
|
14
14
|
export { API_EVENT as GUIDE_API_EVENT, GUIDE_EVENT_PREFIX, GUIDE_LAYER_ATTRIBUTE, apiCallDetail, emitGuideEvent, guideAnchor, reportApiCall, reportApiEvent, type ApiCallReport, type ApiEventDetail, type GuideAnchorProps, } from "./events";
|
|
15
|
-
export { openGuidePanel, useGuideEntry, type GuideEntry } from "./guide-store";
|
|
15
|
+
export { guideMenuItems, guideMenuShown, openGuidePanel, openPageGuide, openPagesPanel, useGuideEntry, usePageGuideEntry, usePageGuides, type GuideEntry, type GuideMenuItem, type PageGuidesEntry, } from "./guide-store";
|
|
16
16
|
export { GuideRuntime, type GuideMenu, type GuideRouting, type GuideRuntimeProps, } from "./guide-runtime";
|
|
17
17
|
export { GuideProgressConflict, loadGuides, storeGuides, type GuideProgressAdapter, type GuideProgressRequest, type GuideProgressResponse, } from "./progress-sync";
|
|
18
|
-
export type { GuideAudience, GuideMode } from "./progress";
|
|
18
|
+
export type { GuideAudience, GuideMode, PagesMode } from "./progress";
|
|
19
19
|
export { matchApiPath, matchRoute, fillRoute } from "./patterns";
|
|
@@ -10,7 +10,48 @@ export interface GuideEntry {
|
|
|
10
10
|
}
|
|
11
11
|
/** Called by the host: the entry to show (null: none), and how to open the panel. */
|
|
12
12
|
export declare function publishGuideEntry(next: GuideEntry | null, openPanel: (() => void) | null): void;
|
|
13
|
+
/**
|
|
14
|
+
* Page guides here, for the "?" menu: this page's guide (its title) and how
|
|
15
|
+
* many page guides the panel lists ("คู่มือทุกหน้า"). Shell ≥ 0.1.74.
|
|
16
|
+
*/
|
|
17
|
+
export interface PageGuidesEntry {
|
|
18
|
+
/** This page's guide for this person, or null. */
|
|
19
|
+
page: {
|
|
20
|
+
title: string;
|
|
21
|
+
} | null;
|
|
22
|
+
/** Page guides with an `href` this person has (the panel's list). */
|
|
23
|
+
listed: number;
|
|
24
|
+
}
|
|
25
|
+
/** Called by the host: this page's guide and the listed count, and how to open them. */
|
|
26
|
+
export declare function publishPageGuides(next: PageGuidesEntry | null, openPage: (() => void) | null, openPages: (() => void) | null): void;
|
|
27
|
+
/** The "?" menu's items, in order (pure: the menu and its tests share it). */
|
|
28
|
+
export type GuideMenuItem = "page" | "missions" | "pages" | "help";
|
|
29
|
+
export declare function guideMenuItems(e: GuideEntry | null, p?: PageGuidesEntry): GuideMenuItem[];
|
|
30
|
+
/**
|
|
31
|
+
* Whether the "?" press opens a menu rather than the help dialog: a tour
|
|
32
|
+
* with missions shown, a guide for this page, or page guides to list. A tour
|
|
33
|
+
* whose missions are all hidden for this user (`visible`, e.g. Plannex
|
|
34
|
+
* without an employee record) has nothing to open, and "0/0" led to an
|
|
35
|
+
* empty panel. The entry itself stays published: apps wait on it before
|
|
36
|
+
* they load the facts that make missions visible.
|
|
37
|
+
*/
|
|
38
|
+
export declare function guideMenuShown(e: GuideEntry | null, p?: PageGuidesEntry): boolean;
|
|
13
39
|
/** Opens the tour's quest panel, when this user has a tour here. */
|
|
14
40
|
export declare function openGuidePanel(): void;
|
|
15
41
|
/** The "?" menu's entry, or null when there is no tour for this user. */
|
|
16
42
|
export declare function useGuideEntry(): GuideEntry | null;
|
|
43
|
+
/** Opens this page's guide ("คู่มือหน้านี้"), when there is one. */
|
|
44
|
+
export declare function openPageGuide(): void;
|
|
45
|
+
/** Opens the panel on the page guides alone ("คู่มือทุกหน้า"). */
|
|
46
|
+
export declare function openPagesPanel(): void;
|
|
47
|
+
/** Page guides here (this page's, and the listed count); stable until they change. */
|
|
48
|
+
export declare function usePageGuides(): PageGuidesEntry;
|
|
49
|
+
/**
|
|
50
|
+
* This page's guide: `{ title, open }`, or null when the page (or the
|
|
51
|
+
* sub-screen, `when`) has none for this person. For an app that draws its
|
|
52
|
+
* own "?" (LIFF's page head): draw it only when this is not null.
|
|
53
|
+
*/
|
|
54
|
+
export declare function usePageGuideEntry(): {
|
|
55
|
+
title: string;
|
|
56
|
+
open: () => void;
|
|
57
|
+
} | null;
|
|
@@ -10,4 +10,4 @@
|
|
|
10
10
|
* before 0.1.68: 16px from the bottom (+ the safe area) on a phone, 22px on
|
|
11
11
|
* desktop.
|
|
12
12
|
*/
|
|
13
|
-
export declare const GUIDE_CSS = "\n[data-erp-guide-layer]{position:fixed;inset:0;z-index:1000;pointer-events:none;font-family:inherit;color:var(--popover-foreground,#1c2634);\n --eg-scrim:rgba(12,20,34,.64);--eg-card:var(--popover,#fff);--eg-fg:var(--popover-foreground,#1c2634);\n --eg-muted:var(--muted-foreground,#6d7886);--eg-soft:var(--muted,#eef3f9);--eg-line:var(--border,#e8ecf1);\n --eg-primary:var(--primary,#3280dd);--eg-on-primary:var(--primary-foreground,#fff);\n --eg-tint:color-mix(in oklab,var(--eg-primary) 13%,var(--eg-card));--eg-strong:color-mix(in oklab,var(--eg-primary) 82%,#000);\n --eg-danger:var(--destructive,#d23b4b);--eg-ok:#1d9a5f;--eg-gold:#e6a417;\n --eg-shadow:0 18px 50px -12px rgba(16,32,64,.35),0 4px 12px rgba(16,32,64,.08);line-height:1.5;font-size:14px}\n[data-erp-guide-layer] *{box-sizing:border-box}\n[data-erp-guide-layer] button{font:inherit;color:inherit;cursor:pointer}\n.eg-i{pointer-events:auto}\n.eg-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n.eg-scrim-svg{position:fixed;inset:0;width:100%;height:100%;pointer-events:none;overflow:visible}\n.eg-scrim-svg .eg-scrim-fill{fill:var(--eg-scrim);pointer-events:none}\n.eg-scrim-svg .eg-scrim-hit{fill:transparent;pointer-events:all}\n.eg-scrim{position:fixed;inset:0;background:var(--eg-scrim);pointer-events:auto}\n.eg-scrim.eg-light{background:rgba(12,20,34,.45)}\n.eg-scrim.eg-faint{background:rgba(12,20,34,.35)}\n.eg-ring{position:fixed;border-radius:12px;pointer-events:none;box-shadow:0 0 0 3px #fff,0 0 0 6px var(--eg-primary)}\n.eg-ring.eg-move{transition:left .26s ease,top .26s ease,width .26s ease,height .26s ease}\n.eg-ring::after{content:\"\";position:absolute;inset:-6px;border-radius:15px;border:3px solid var(--eg-primary);animation:eg-pulse 1.6s ease-out infinite}\n.eg-ring.eg-flash::after{animation:eg-flash .5s ease 1}\n@keyframes eg-pulse{0%{opacity:.9;transform:scale(1)}100%{opacity:0;transform:scale(1.12)}}\n@keyframes eg-flash{0%,100%{opacity:1;transform:none}50%{opacity:.2}}\n.eg-hand{position:fixed;width:46px;height:46px;pointer-events:none;filter:drop-shadow(0 4px 6px rgba(0,0,0,.35));animation:eg-tap 1.1s ease-in-out infinite}\n.eg-hand svg{width:46px;height:46px;fill:#fff;stroke:#1c2634;stroke-width:1.4;stroke-linejoin:round;stroke-linecap:round}\n.eg-hand.eg-flip svg{transform:scaleY(-1)}\n@keyframes eg-tap{0%,100%{transform:translate(6px,8px)}50%{transform:translate(0,0)}}\n.eg-bubble{position:fixed;left:0;top:0;width:320px;background:var(--eg-card);color:var(--eg-fg);border-radius:14px;box-shadow:var(--eg-shadow);padding:14px 16px 12px;border-top:4px solid var(--eg-primary);outline:none;pointer-events:auto}\n.eg-bubble.eg-err{border-top-color:var(--eg-danger)}\n.eg-bubble.eg-nudge{animation:eg-nudge .38s ease}\n@keyframes eg-nudge{0%,100%{translate:0}20%{translate:-7px}40%{translate:6px}60%{translate:-4px}80%{translate:2px}}\n.eg-b-top{display:flex;justify-content:space-between;align-items:center;gap:8px;font-size:12px;color:var(--eg-muted)}\n.eg-b-top .eg-mis{font-weight:600;color:var(--eg-strong);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.eg-b-top .eg-cnt{white-space:nowrap;font-weight:600}\n.eg-pips{display:flex;gap:4px;margin:8px 0 10px}\n.eg-pips i{flex:1;height:4px;border-radius:2px;background:var(--eg-soft)}\n.eg-pips i.eg-d{background:var(--eg-primary)}\n.eg-pips i.eg-c{background:color-mix(in oklab,var(--eg-primary) 45%,var(--eg-card))}\n.eg-b-t{margin:0;font-size:16px;font-weight:600;line-height:1.45}\n.eg-b-w{margin:2px 0 0;font-size:13.5px;color:var(--eg-muted)}\n.eg-bubble.eg-err .eg-b-t{color:var(--eg-danger)}\n.eg-k{display:inline-block;background:var(--eg-tint);color:var(--eg-strong);border-radius:7px;padding:0 7px;font-weight:600}\n.eg-b-f{display:flex;align-items:center;justify-content:space-between;margin-top:12px;gap:8px}\n.eg-b-f .eg-btn{height:34px;padding:0 14px;font-size:13.5px}\n.eg-exit{border:0;background:none;color:var(--eg-muted);font-size:12.5px;padding:4px 0;text-decoration:underline;text-underline-offset:3px}\n.eg-exit:hover{color:var(--eg-fg)}\n.eg-arrow{position:absolute;width:14px;height:14px;background:var(--eg-card);transform:rotate(45deg);border-radius:2px}\n.eg-arrow.eg-top{background:var(--eg-primary)}\n.eg-bubble.eg-err .eg-arrow.eg-top{background:var(--eg-danger)}\n.eg-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:40px;padding:0 16px;border-radius:10px;border:1px solid transparent;font-size:14px;font-weight:600;white-space:nowrap}\n.eg-btn:focus-visible,.eg-exit:focus-visible,.eg-chip:focus-visible,.eg-x:focus-visible{outline:2px solid var(--eg-primary);outline-offset:2px}\n.eg-primary{background:var(--eg-primary);color:var(--eg-on-primary)!important}\n.eg-primary:hover{background:var(--eg-strong)}\n.eg-primary[disabled]{opacity:.55;cursor:default}\n.eg-ghost{background:var(--eg-card);border-color:var(--eg-line)}\n.eg-ghost:hover{background:var(--eg-soft)}\n.eg-ghost[disabled]{opacity:.55;cursor:default}\n.eg-link{background:none;border:0;color:var(--eg-muted);font-weight:500;padding:0 6px;height:32px}\n.eg-link:hover{color:var(--eg-fg);text-decoration:underline}\n.eg-modal{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);width:min(440px,calc(100vw - 32px));max-height:calc(100vh - 32px);overflow:auto;background:var(--eg-card);color:var(--eg-fg);border-radius:20px;box-shadow:var(--eg-shadow);padding:28px 28px 22px;text-align:center;outline:none;pointer-events:auto}\n.eg-modal.eg-pop{animation:eg-pop .32s cubic-bezier(.2,.9,.3,1.3)}\n@keyframes eg-pop{from{opacity:0;transform:translate(-50%,-46%) scale(.94)}}\n.eg-modal h2{margin:6px 0 4px;font-size:22px;font-weight:700;letter-spacing:-.2px;line-height:1.3}\n.eg-modal .eg-sub{margin:0;color:var(--eg-muted);font-size:14.5px}\n.eg-eyebrow{margin:0;font-size:12.5px;font-weight:600;letter-spacing:.3px;color:var(--eg-strong)}\n.eg-actions{display:grid;gap:6px;margin-top:20px}\n.eg-actions .eg-btn{height:44px}\n.eg-badge{width:64px;height:64px;border-radius:18px;margin:0 auto 12px;display:grid;place-items:center;background:var(--eg-tint);color:var(--eg-strong)}\n.eg-badge svg.eg-ic{width:30px;height:30px}\n.eg-quests{list-style:none;padding:0;margin:18px 0 0;text-align:left;display:grid;gap:6px}\n.eg-quests li{display:flex;align-items:center;gap:12px;padding:9px 12px;border-radius:11px;background:var(--eg-soft);font-size:14px}\n.eg-quests li .eg-n{width:26px;height:26px;border-radius:50%;background:var(--eg-card);border:1.5px solid var(--eg-line);display:grid;place-items:center;font-size:12px;font-weight:700;color:var(--eg-muted);flex:none}\n.eg-quests li.eg-first{background:var(--eg-tint)}\n.eg-quests li.eg-first .eg-n{border-color:var(--eg-primary);color:var(--eg-strong)}\n.eg-quests li.eg-ok .eg-n{background:var(--eg-ok);border-color:var(--eg-ok);color:#fff}\n.eg-quests li .eg-n svg.eg-ic{width:15px;height:15px;stroke-width:3}\n.eg-quests li .eg-t{flex:1}\n.eg-quests li small{color:var(--eg-muted);font-size:12px;white-space:nowrap}\n.eg-modal.eg-confirm{text-align:left;width:min(380px,calc(100vw - 32px));padding:22px}\n.eg-modal.eg-confirm h2{font-size:18px;margin-top:0}\n.eg-modal.eg-confirm .eg-actions{grid-template-columns:1fr 1fr}\n.eg-medal{width:84px;height:84px;border-radius:50%;margin:4px auto 10px;display:grid;place-items:center;color:#fff;background:radial-gradient(circle at 35% 30%,#ffd666,var(--eg-gold));box-shadow:0 0 0 8px #fff4d6;animation:eg-stamp .5s cubic-bezier(.2,.9,.3,1.4) .1s both}\n.eg-medal svg.eg-ic{width:42px;height:42px;stroke-width:2.6}\n@keyframes eg-stamp{from{transform:scale(.3) rotate(-25deg);opacity:0}}\n.eg-prog{display:flex;align-items:center;gap:10px;margin-top:16px;font-size:13px;color:var(--eg-muted);font-weight:600}\n.eg-prog .eg-bar{flex:1;height:8px;border-radius:4px;background:var(--eg-soft);overflow:hidden}\n.eg-prog .eg-bar i{display:block;height:100%;background:var(--eg-primary);border-radius:4px;transition:width .9s cubic-bezier(.2,.8,.2,1) .35s}\n.eg-burst{position:absolute;left:50%;top:70px;width:0;height:0;pointer-events:none}\n.eg-burst span{position:absolute;width:8px;height:12px;border-radius:2px;opacity:0;animation:eg-conf 1.1s cubic-bezier(.15,.7,.3,1) forwards}\n@keyframes eg-conf{0%{opacity:1;transform:translate(0,0) rotate(0)}100%{opacity:0;transform:translate(var(--x),var(--y)) rotate(var(--r))}}\n.eg-card{position:fixed;left:50%;bottom:calc(var(--erp-guide-bottom-offset,16px) + 12px);transform:translateX(-50%);width:min(360px,calc(100vw - 32px));background:var(--eg-card);color:var(--eg-fg);border-radius:14px;box-shadow:var(--eg-shadow);padding:14px 16px;border-top:4px solid var(--eg-primary);pointer-events:auto;outline:none}\n.eg-card .eg-row{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:12px}\n.eg-loading{display:flex;align-items:center;gap:10px;font-weight:600}\n.eg-spin{width:18px;height:18px;border-radius:50%;border:2.5px solid var(--eg-soft);border-top-color:var(--eg-primary);animation:eg-spin .8s linear infinite;flex:none}\n@keyframes eg-spin{to{transform:rotate(360deg)}}\n.eg-chip{position:fixed;right:22px;bottom:var(--erp-guide-bottom-offset,22px);display:flex;align-items:center;gap:10px;height:48px;padding:0 18px 0 8px;border-radius:24px;border:1px solid var(--eg-line);background:var(--eg-card);color:var(--eg-fg);box-shadow:0 8px 24px -8px rgba(16,32,64,.3);font-weight:600;font-size:14px;pointer-events:auto}\n.eg-chip svg{width:34px;height:34px}\n.eg-chip.eg-hi{animation:eg-hi 1.2s ease 2}\n@keyframes eg-hi{50%{box-shadow:0 0 0 6px color-mix(in oklab,var(--eg-primary) 35%,transparent),0 8px 24px -8px rgba(16,32,64,.3)}}\n.eg-panel{position:fixed;right:22px;bottom:calc(var(--erp-guide-bottom-offset,22px) + 60px);width:360px;max-height:calc(100vh - 110px);overflow:auto;background:var(--eg-card);color:var(--eg-fg);border:1px solid var(--eg-line);border-radius:16px;box-shadow:var(--eg-shadow);outline:none;pointer-events:auto}\n.eg-panel-bd{display:none}\n.eg-q-h{display:flex;align-items:center;gap:10px;padding:16px 12px 4px 18px}\n.eg-q-h h2{margin:0;font-size:16px;font-weight:700;flex:1}\n.eg-q-h .eg-n{font-size:13px;color:var(--eg-muted);font-weight:600}\n.eg-x{width:34px;height:34px;border-radius:10px;border:0;background:none;display:grid;place-items:center;color:var(--eg-muted)}\n.eg-x:hover{background:var(--eg-soft)}\n.eg-x svg.eg-ic{width:18px;height:18px}\n.eg-panel .eg-prog{margin:6px 18px 8px}\n.eg-q-list{list-style:none;margin:0;padding:4px 10px 6px;display:grid;gap:2px}\n.eg-q-item{display:flex;align-items:center;gap:12px;padding:10px 8px;border-radius:11px}\n.eg-q-item.eg-next{background:var(--eg-tint)}\n.eg-q-item .eg-n{width:30px;height:30px;border-radius:50%;border:1.5px solid var(--eg-line);display:grid;place-items:center;font-size:12.5px;font-weight:700;color:var(--eg-muted);flex:none;background:var(--eg-card)}\n.eg-q-item.eg-next .eg-n{border-color:var(--eg-primary);color:var(--eg-strong)}\n.eg-q-item.eg-done .eg-n{background:var(--eg-ok);border-color:var(--eg-ok);color:#fff}\n.eg-q-item.eg-done .eg-n svg.eg-ic{width:16px;height:16px;stroke-width:3}\n.eg-q-item.eg-dim .eg-n{opacity:.55}\n.eg-q-item.eg-just .eg-n{animation:eg-stamp .55s cubic-bezier(.2,.9,.3,1.4) .2s both}\n.eg-q-item .eg-t{flex:1;min-width:0}\n.eg-q-item .eg-t b{display:block;font-size:14px;font-weight:600}\n.eg-q-item.eg-done .eg-t b{color:var(--eg-muted)}\n.eg-q-item .eg-t small{display:block;font-size:12px;color:var(--eg-muted)}\n.eg-q-item .eg-t small.eg-sk{color:#b06a00}\n.eg-q-item .eg-t small.eg-lock{color:var(--eg-fg);font-weight:500}\n.eg-q-item .eg-btn{height:32px;padding:0 12px;font-size:13px}\n.eg-q-acts{display:flex;flex-direction:column;align-items:flex-end;gap:2px}\n.eg-q-acts .eg-link{height:22px;font-size:12px;padding:0 2px}\n.eg-q-f{border-top:1px solid var(--eg-line);padding:8px 12px;display:flex;justify-content:flex-end}\n.eg-toast{position:fixed;left:50%;bottom:calc(var(--erp-guide-bottom-offset,22px) + 62px);transform:translateX(-50%);background:#1c2634;color:#fff;padding:10px 16px;border-radius:10px;font-size:13.5px;box-shadow:var(--eg-shadow);max-width:calc(100vw - 32px);pointer-events:none}\nsvg.eg-ic{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;flex:none}\n@media (max-width:767px){\n .eg-bubble{width:auto}\n .eg-arrow{display:none}\n .eg-modal{top:auto;bottom:12px;transform:translateX(-50%);width:calc(100vw - 24px);padding:24px 20px 18px}\n .eg-modal.eg-pop{animation:eg-up .3s cubic-bezier(.2,.9,.3,1.1)}\n .eg-modal .eg-actions .eg-btn{height:46px}\n .eg-chip{right:16px;bottom:var(--erp-guide-bottom-offset,calc(16px + env(safe-area-inset-bottom)))}\n .eg-panel-bd{display:block;position:fixed;inset:0;background:rgba(15,23,42,.38);pointer-events:auto}\n .eg-panel{left:0;right:0;bottom:0;width:100%;max-height:85vh;border-radius:18px 18px 0 0;padding-bottom:env(safe-area-inset-bottom)}\n .eg-q-item{padding:12px 8px}\n .eg-card{bottom:calc(var(--erp-guide-bottom-offset,calc(16px + env(safe-area-inset-bottom))) - 4px)}\n .eg-toast{bottom:calc(var(--erp-guide-bottom-offset,calc(16px + env(safe-area-inset-bottom))) + 60px)}\n}\n@keyframes eg-up{from{opacity:0;transform:translate(-50%,30px)}}\n@media (prefers-reduced-motion:reduce){\n [data-erp-guide-layer] *,[data-erp-guide-layer] *::before,[data-erp-guide-layer] *::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}\n .eg-ring::after{animation:none!important;opacity:1;transform:none}\n .eg-ring.eg-flash::after{animation:eg-flash .5s ease 1!important;animation-duration:.5s!important}\n .eg-hand{animation:none!important;transform:translate(4px,6px)}\n .eg-burst{display:none}\n .eg-bubble.eg-nudge{animation:none!important;border-top-color:var(--eg-danger)}\n}\n";
|
|
13
|
+
export declare const GUIDE_CSS = "\n[data-erp-guide-layer]{position:fixed;inset:0;z-index:1000;pointer-events:none;font-family:inherit;color:var(--popover-foreground,#1c2634);\n --eg-scrim:rgba(12,20,34,.64);--eg-card:var(--popover,#fff);--eg-fg:var(--popover-foreground,#1c2634);\n --eg-muted:var(--muted-foreground,#6d7886);--eg-soft:var(--muted,#eef3f9);--eg-line:var(--border,#e8ecf1);\n --eg-primary:var(--primary,#3280dd);--eg-on-primary:var(--primary-foreground,#fff);\n --eg-tint:color-mix(in oklab,var(--eg-primary) 13%,var(--eg-card));--eg-strong:color-mix(in oklab,var(--eg-primary) 82%,#000);\n --eg-danger:var(--destructive,#d23b4b);--eg-ok:#1d9a5f;--eg-gold:#e6a417;\n --eg-shadow:0 18px 50px -12px rgba(16,32,64,.35),0 4px 12px rgba(16,32,64,.08);line-height:1.5;font-size:14px}\n[data-erp-guide-layer] *{box-sizing:border-box}\n[data-erp-guide-layer] button{font:inherit;color:inherit;cursor:pointer}\n.eg-i{pointer-events:auto}\n.eg-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n.eg-scrim-svg{position:fixed;inset:0;width:100%;height:100%;pointer-events:none;overflow:visible}\n.eg-scrim-svg .eg-scrim-fill{fill:var(--eg-scrim);pointer-events:none}\n.eg-scrim-svg .eg-scrim-hit{fill:transparent;pointer-events:all}\n.eg-scrim{position:fixed;inset:0;background:var(--eg-scrim);pointer-events:auto}\n.eg-scrim.eg-light{background:rgba(12,20,34,.45)}\n.eg-scrim.eg-faint{background:rgba(12,20,34,.35)}\n.eg-ring{position:fixed;border-radius:12px;pointer-events:none;box-shadow:0 0 0 3px #fff,0 0 0 6px var(--eg-primary)}\n.eg-ring.eg-move{transition:left .26s ease,top .26s ease,width .26s ease,height .26s ease}\n.eg-ring::after{content:\"\";position:absolute;inset:-6px;border-radius:15px;border:3px solid var(--eg-primary);animation:eg-pulse 1.6s ease-out infinite}\n.eg-ring.eg-flash::after{animation:eg-flash .5s ease 1}\n@keyframes eg-pulse{0%{opacity:.9;transform:scale(1)}100%{opacity:0;transform:scale(1.12)}}\n@keyframes eg-flash{0%,100%{opacity:1;transform:none}50%{opacity:.2}}\n.eg-hand{position:fixed;width:46px;height:46px;pointer-events:none;filter:drop-shadow(0 4px 6px rgba(0,0,0,.35));animation:eg-tap 1.1s ease-in-out infinite}\n.eg-hand svg{width:46px;height:46px;fill:#fff;stroke:#1c2634;stroke-width:1.4;stroke-linejoin:round;stroke-linecap:round}\n.eg-hand.eg-flip svg{transform:scaleY(-1)}\n@keyframes eg-tap{0%,100%{transform:translate(6px,8px)}50%{transform:translate(0,0)}}\n.eg-bubble{position:fixed;left:0;top:0;width:320px;background:var(--eg-card);color:var(--eg-fg);border-radius:14px;box-shadow:var(--eg-shadow);padding:14px 16px 12px;border-top:4px solid var(--eg-primary);outline:none;pointer-events:auto}\n.eg-bubble.eg-err{border-top-color:var(--eg-danger)}\n.eg-bubble.eg-nudge{animation:eg-nudge .38s ease}\n@keyframes eg-nudge{0%,100%{translate:0}20%{translate:-7px}40%{translate:6px}60%{translate:-4px}80%{translate:2px}}\n.eg-b-top{display:flex;justify-content:space-between;align-items:center;gap:8px;font-size:12px;color:var(--eg-muted)}\n.eg-b-top .eg-mis{font-weight:600;color:var(--eg-strong);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.eg-b-top .eg-cnt{white-space:nowrap;font-weight:600}\n.eg-pips{display:flex;gap:4px;margin:8px 0 10px}\n.eg-pips i{flex:1;height:4px;border-radius:2px;background:var(--eg-soft)}\n.eg-pips i.eg-d{background:var(--eg-primary)}\n.eg-pips i.eg-c{background:color-mix(in oklab,var(--eg-primary) 45%,var(--eg-card))}\n.eg-b-t{margin:0;font-size:16px;font-weight:600;line-height:1.45}\n.eg-b-w{margin:2px 0 0;font-size:13.5px;color:var(--eg-muted)}\n.eg-bubble.eg-err .eg-b-t{color:var(--eg-danger)}\n.eg-b-s{margin:6px 0 0;font-size:13px;font-weight:600;color:var(--eg-danger)}\n.eg-k{display:inline-block;background:var(--eg-tint);color:var(--eg-strong);border-radius:7px;padding:0 7px;font-weight:600}\n.eg-b-f{display:flex;align-items:center;justify-content:space-between;margin-top:12px;gap:8px}\n.eg-b-f .eg-btn{height:34px;padding:0 14px;font-size:13.5px}\n.eg-exit{border:0;background:none;color:var(--eg-muted);font-size:12.5px;padding:4px 0;text-decoration:underline;text-underline-offset:3px}\n.eg-exit:hover{color:var(--eg-fg)}\n.eg-arrow{position:absolute;width:14px;height:14px;background:var(--eg-card);transform:rotate(45deg);border-radius:2px}\n.eg-arrow.eg-top{background:var(--eg-primary)}\n.eg-bubble.eg-err .eg-arrow.eg-top{background:var(--eg-danger)}\n.eg-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:40px;padding:0 16px;border-radius:10px;border:1px solid transparent;font-size:14px;font-weight:600;white-space:nowrap}\n.eg-btn:focus-visible,.eg-exit:focus-visible,.eg-chip:focus-visible,.eg-x:focus-visible{outline:2px solid var(--eg-primary);outline-offset:2px}\n.eg-primary{background:var(--eg-primary);color:var(--eg-on-primary)!important}\n.eg-primary:hover{background:var(--eg-strong)}\n.eg-primary[disabled]{opacity:.55;cursor:default}\n.eg-ghost{background:var(--eg-card);border-color:var(--eg-line)}\n.eg-ghost:hover{background:var(--eg-soft)}\n.eg-ghost[disabled]{opacity:.55;cursor:default}\n.eg-link{background:none;border:0;color:var(--eg-muted);font-weight:500;padding:0 6px;height:32px}\n.eg-link:hover{color:var(--eg-fg);text-decoration:underline}\n.eg-modal{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);width:min(440px,calc(100vw - 32px));max-height:calc(100vh - 32px);overflow:auto;background:var(--eg-card);color:var(--eg-fg);border-radius:20px;box-shadow:var(--eg-shadow);padding:28px 28px 22px;text-align:center;outline:none;pointer-events:auto}\n.eg-modal.eg-pop{animation:eg-pop .32s cubic-bezier(.2,.9,.3,1.3)}\n@keyframes eg-pop{from{opacity:0;transform:translate(-50%,-46%) scale(.94)}}\n.eg-modal h2{margin:6px 0 4px;font-size:22px;font-weight:700;letter-spacing:-.2px;line-height:1.3}\n.eg-modal .eg-sub{margin:0;color:var(--eg-muted);font-size:14.5px}\n.eg-eyebrow{margin:0;font-size:12.5px;font-weight:600;letter-spacing:.3px;color:var(--eg-strong)}\n.eg-actions{display:grid;gap:6px;margin-top:20px}\n.eg-actions .eg-btn{height:44px}\n.eg-badge{width:64px;height:64px;border-radius:18px;margin:0 auto 12px;display:grid;place-items:center;background:var(--eg-tint);color:var(--eg-strong)}\n.eg-badge svg.eg-ic{width:30px;height:30px}\n.eg-quests{list-style:none;padding:0;margin:18px 0 0;text-align:left;display:grid;gap:6px}\n.eg-quests li{display:flex;align-items:center;gap:12px;padding:9px 12px;border-radius:11px;background:var(--eg-soft);font-size:14px}\n.eg-quests li .eg-n{width:26px;height:26px;border-radius:50%;background:var(--eg-card);border:1.5px solid var(--eg-line);display:grid;place-items:center;font-size:12px;font-weight:700;color:var(--eg-muted);flex:none}\n.eg-quests li.eg-first{background:var(--eg-tint)}\n.eg-quests li.eg-first .eg-n{border-color:var(--eg-primary);color:var(--eg-strong)}\n.eg-quests li.eg-ok .eg-n{background:var(--eg-ok);border-color:var(--eg-ok);color:#fff}\n.eg-quests li .eg-n svg.eg-ic{width:15px;height:15px;stroke-width:3}\n.eg-quests li .eg-t{flex:1}\n.eg-quests li small{color:var(--eg-muted);font-size:12px;white-space:nowrap}\n.eg-modal.eg-confirm{text-align:left;width:min(380px,calc(100vw - 32px));padding:22px}\n.eg-modal.eg-confirm h2{font-size:18px;margin-top:0}\n.eg-modal.eg-confirm .eg-actions{grid-template-columns:1fr 1fr}\n.eg-medal{width:84px;height:84px;border-radius:50%;margin:4px auto 10px;display:grid;place-items:center;color:#fff;background:radial-gradient(circle at 35% 30%,#ffd666,var(--eg-gold));box-shadow:0 0 0 8px #fff4d6;animation:eg-stamp .5s cubic-bezier(.2,.9,.3,1.4) .1s both}\n.eg-medal svg.eg-ic{width:42px;height:42px;stroke-width:2.6}\n@keyframes eg-stamp{from{transform:scale(.3) rotate(-25deg);opacity:0}}\n.eg-prog{display:flex;align-items:center;gap:10px;margin-top:16px;font-size:13px;color:var(--eg-muted);font-weight:600}\n.eg-prog .eg-bar{flex:1;height:8px;border-radius:4px;background:var(--eg-soft);overflow:hidden}\n.eg-prog .eg-bar i{display:block;height:100%;background:var(--eg-primary);border-radius:4px;transition:width .9s cubic-bezier(.2,.8,.2,1) .35s}\n.eg-burst{position:absolute;left:50%;top:70px;width:0;height:0;pointer-events:none}\n.eg-burst span{position:absolute;width:8px;height:12px;border-radius:2px;opacity:0;animation:eg-conf 1.1s cubic-bezier(.15,.7,.3,1) forwards}\n@keyframes eg-conf{0%{opacity:1;transform:translate(0,0) rotate(0)}100%{opacity:0;transform:translate(var(--x),var(--y)) rotate(var(--r))}}\n.eg-card{position:fixed;left:50%;bottom:calc(var(--erp-guide-bottom-offset,16px) + 12px);transform:translateX(-50%);width:min(360px,calc(100vw - 32px));background:var(--eg-card);color:var(--eg-fg);border-radius:14px;box-shadow:var(--eg-shadow);padding:14px 16px;border-top:4px solid var(--eg-primary);pointer-events:auto;outline:none}\n.eg-card .eg-row{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:12px}\n.eg-loading{display:flex;align-items:center;gap:10px;font-weight:600}\n.eg-spin{width:18px;height:18px;border-radius:50%;border:2.5px solid var(--eg-soft);border-top-color:var(--eg-primary);animation:eg-spin .8s linear infinite;flex:none}\n@keyframes eg-spin{to{transform:rotate(360deg)}}\n.eg-chip{position:fixed;right:22px;bottom:var(--erp-guide-bottom-offset,22px);display:flex;align-items:center;gap:10px;height:48px;padding:0 18px 0 8px;border-radius:24px;border:1px solid var(--eg-line);background:var(--eg-card);color:var(--eg-fg);box-shadow:0 8px 24px -8px rgba(16,32,64,.3);font-weight:600;font-size:14px;pointer-events:auto}\n.eg-chip svg{width:34px;height:34px}\n.eg-chip.eg-hi{animation:eg-hi 1.2s ease 2}\n@keyframes eg-hi{50%{box-shadow:0 0 0 6px color-mix(in oklab,var(--eg-primary) 35%,transparent),0 8px 24px -8px rgba(16,32,64,.3)}}\n.eg-panel{position:fixed;right:22px;bottom:calc(var(--erp-guide-bottom-offset,22px) + 60px);width:360px;max-height:calc(100vh - 110px);overflow:auto;background:var(--eg-card);color:var(--eg-fg);border:1px solid var(--eg-line);border-radius:16px;box-shadow:var(--eg-shadow);outline:none;pointer-events:auto}\n.eg-panel-bd{display:none}\n.eg-q-h{display:flex;align-items:center;gap:10px;padding:16px 12px 4px 18px}\n.eg-q-h h2{margin:0;font-size:16px;font-weight:700;flex:1}\n.eg-q-h .eg-n{font-size:13px;color:var(--eg-muted);font-weight:600}\n.eg-x{width:34px;height:34px;border-radius:10px;border:0;background:none;display:grid;place-items:center;color:var(--eg-muted)}\n.eg-x:hover{background:var(--eg-soft)}\n.eg-x svg.eg-ic{width:18px;height:18px}\n.eg-panel .eg-prog{margin:6px 18px 8px}\n.eg-q-list{list-style:none;margin:0;padding:4px 10px 6px;display:grid;gap:2px}\n.eg-q-item{display:flex;align-items:center;gap:12px;padding:10px 8px;border-radius:11px}\n.eg-q-item.eg-next{background:var(--eg-tint)}\n.eg-q-item .eg-n{width:30px;height:30px;border-radius:50%;border:1.5px solid var(--eg-line);display:grid;place-items:center;font-size:12.5px;font-weight:700;color:var(--eg-muted);flex:none;background:var(--eg-card)}\n.eg-q-item.eg-next .eg-n{border-color:var(--eg-primary);color:var(--eg-strong)}\n.eg-q-item.eg-done .eg-n{background:var(--eg-ok);border-color:var(--eg-ok);color:#fff}\n.eg-q-item.eg-done .eg-n svg.eg-ic{width:16px;height:16px;stroke-width:3}\n.eg-q-item.eg-dim .eg-n{opacity:.55}\n.eg-q-item.eg-just .eg-n{animation:eg-stamp .55s cubic-bezier(.2,.9,.3,1.4) .2s both}\n.eg-q-item .eg-t{flex:1;min-width:0}\n.eg-q-item .eg-t b{display:block;font-size:14px;font-weight:600}\n.eg-q-item.eg-done .eg-t b{color:var(--eg-muted)}\n.eg-q-item .eg-t small{display:block;font-size:12px;color:var(--eg-muted)}\n.eg-q-item .eg-t small.eg-sk{color:#b06a00}\n.eg-q-item .eg-t small.eg-lock{color:var(--eg-fg);font-weight:500}\n.eg-q-item .eg-btn{height:32px;padding:0 12px;font-size:13px}\n.eg-q-acts{display:flex;flex-direction:column;align-items:flex-end;gap:2px}\n.eg-q-acts .eg-link{height:22px;font-size:12px;padding:0 2px}\n.eg-q-f{border-top:1px solid var(--eg-line);padding:8px 12px;display:flex;justify-content:flex-end}\n.eg-q-sub{margin:6px 0 0;padding:12px 18px 2px;border-top:1px solid var(--eg-line);font-size:13px;font-weight:700;color:var(--eg-muted)}\n.eg-pg-item{padding:8px}\n.eg-pg-item .eg-t small.eg-new{color:var(--eg-strong);font-weight:600}\n.eg-card.eg-offer{left:auto;right:22px;transform:none;bottom:var(--erp-guide-bottom-offset,22px);width:min(320px,calc(100vw - 32px))}\n.eg-offer .eg-po-e{margin:0 0 2px;font-size:12px;font-weight:600;color:var(--eg-strong)}\n.eg-offer .eg-row .eg-btn{height:34px;padding:0 14px;font-size:13.5px}\n.eg-toast{position:fixed;left:50%;bottom:calc(var(--erp-guide-bottom-offset,22px) + 62px);transform:translateX(-50%);background:#1c2634;color:#fff;padding:10px 16px;border-radius:10px;font-size:13.5px;box-shadow:var(--eg-shadow);max-width:calc(100vw - 32px);pointer-events:none}\nsvg.eg-ic{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;flex:none}\n@media (max-width:767px){\n .eg-bubble{width:auto}\n .eg-arrow{display:none}\n .eg-modal{top:auto;bottom:12px;transform:translateX(-50%);width:calc(100vw - 24px);padding:24px 20px 18px}\n .eg-modal.eg-pop{animation:eg-up .3s cubic-bezier(.2,.9,.3,1.1)}\n .eg-modal .eg-actions .eg-btn{height:46px}\n .eg-chip{right:16px;bottom:var(--erp-guide-bottom-offset,calc(16px + env(safe-area-inset-bottom)))}\n .eg-panel-bd{display:block;position:fixed;inset:0;background:rgba(15,23,42,.38);pointer-events:auto}\n .eg-panel{left:0;right:0;bottom:0;width:100%;max-height:85vh;border-radius:18px 18px 0 0;padding-bottom:env(safe-area-inset-bottom)}\n .eg-q-item{padding:12px 8px}\n .eg-card{bottom:calc(var(--erp-guide-bottom-offset,calc(16px + env(safe-area-inset-bottom))) - 4px)}\n .eg-card.eg-offer{left:16px;right:16px;width:auto;bottom:calc(var(--erp-guide-bottom-offset,calc(16px + env(safe-area-inset-bottom))) - 4px)}\n .eg-toast{bottom:calc(var(--erp-guide-bottom-offset,calc(16px + env(safe-area-inset-bottom))) + 60px)}\n}\n@keyframes eg-up{from{opacity:0;transform:translate(-50%,30px)}}\n@media (prefers-reduced-motion:reduce){\n [data-erp-guide-layer] *,[data-erp-guide-layer] *::before,[data-erp-guide-layer] *::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}\n .eg-ring::after{animation:none!important;opacity:1;transform:none}\n .eg-ring.eg-flash::after{animation:eg-flash .5s ease 1!important;animation-duration:.5s!important}\n .eg-hand{animation:none!important;transform:translate(4px,6px)}\n .eg-burst{display:none}\n .eg-bubble.eg-nudge{animation:none!important;border-top-color:var(--eg-danger)}\n}\n";
|
package/dist/guide/guide-ui.d.ts
CHANGED
|
@@ -56,8 +56,21 @@ export interface BubbleModel {
|
|
|
56
56
|
title: string;
|
|
57
57
|
why: string;
|
|
58
58
|
error: StepError | null;
|
|
59
|
+
/** The step's status line (GuideStep.status), shown under the instruction. */
|
|
60
|
+
status?: string | null;
|
|
59
61
|
showNext: boolean;
|
|
60
62
|
showEndWithoutSave: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* The bubble's top line in place of "ภารกิจ n · title": a page guide's
|
|
65
|
+
* "คู่มือหน้านี้ · <title>". Shell ≥ 0.1.74.
|
|
66
|
+
*/
|
|
67
|
+
heading?: string;
|
|
68
|
+
/** The way out, in place of "จบการทบทวน" / "ออกจากไกด์" (a page guide: "ปิดคู่มือ"). */
|
|
69
|
+
exitLabel?: string;
|
|
70
|
+
/** ย้อนกลับ: a page guide's read step with a step before it. */
|
|
71
|
+
showBack?: boolean;
|
|
72
|
+
/** ถัดไป's label in place of "ถัดไป" (a page guide's last step: "เสร็จ"). */
|
|
73
|
+
nextLabel?: string;
|
|
61
74
|
}
|
|
62
75
|
export interface StepLayerProps {
|
|
63
76
|
/** The spotlight (padded target), or null while there is none to show. */
|
|
@@ -99,6 +112,8 @@ export interface StepLayerProps {
|
|
|
99
112
|
moving: boolean;
|
|
100
113
|
onExit: () => void;
|
|
101
114
|
onNext: () => void;
|
|
115
|
+
/** ย้อนกลับ (BubbleModel.showBack). */
|
|
116
|
+
onBack?: () => void;
|
|
102
117
|
onEndWithoutSave: () => void;
|
|
103
118
|
onRetry: () => void;
|
|
104
119
|
onGoResume: () => void;
|
|
@@ -168,6 +183,23 @@ export declare function CompleteModal(p: {
|
|
|
168
183
|
reduced: boolean;
|
|
169
184
|
onFinish: () => void;
|
|
170
185
|
}): import("react/jsx-runtime").JSX.Element;
|
|
186
|
+
/**
|
|
187
|
+
* The offer of this page's guide on a first visit: a small card in the
|
|
188
|
+
* corner, not modal (the page stays usable; focus is not taken). Shell ≥ 0.1.74.
|
|
189
|
+
*/
|
|
190
|
+
export declare function PageOfferCard(p: {
|
|
191
|
+
title: string;
|
|
192
|
+
steps: number;
|
|
193
|
+
onStart: () => void;
|
|
194
|
+
onLater: () => void;
|
|
195
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
196
|
+
/** One page guide in the panel's "คู่มือแต่ละหน้า" list. */
|
|
197
|
+
export interface PageItem {
|
|
198
|
+
key: string;
|
|
199
|
+
title: string;
|
|
200
|
+
/** This person has ended this version (ดูแล้ว); otherwise ใหม่. */
|
|
201
|
+
seen: boolean;
|
|
202
|
+
}
|
|
171
203
|
export declare function QuestChip({ done, total, pulse, onOpen }: {
|
|
172
204
|
done: number;
|
|
173
205
|
total: number;
|
|
@@ -199,6 +231,14 @@ export declare function QuestPanel(p: {
|
|
|
199
231
|
onStart: (key: string, replay: boolean) => void;
|
|
200
232
|
onDismiss: (key: string) => void;
|
|
201
233
|
onHideChip: () => void;
|
|
234
|
+
/**
|
|
235
|
+
* The second section, "คู่มือแต่ละหน้า": the page guides this person has
|
|
236
|
+
* (shell ≥ 0.1.74). Omitted or empty: no section.
|
|
237
|
+
*/
|
|
238
|
+
pages?: PageItem[];
|
|
239
|
+
/** false: the page guides alone (no missions for this person, or "คู่มือทุกหน้า"). */
|
|
240
|
+
showMissions?: boolean;
|
|
241
|
+
onOpenPage?: (key: string) => void;
|
|
202
242
|
}): import("react/jsx-runtime").JSX.Element;
|
|
203
243
|
export declare function GuideToast({ text }: {
|
|
204
244
|
text: string;
|
package/dist/guide/machine.d.ts
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { GuideAbortAction, GuideContext, GuideMission, GuideStep, GuideSuite, GuideText, GuideTrigger } from "./types";
|
|
10
10
|
import { type RouteParams } from "./patterns";
|
|
11
|
-
import type { GuideAudience, GuideProgress, MissionEntry } from "./progress";
|
|
11
|
+
import type { GuideAudience, GuideProgress, MissionEntry, PageRow, PagesMode } from "./progress";
|
|
12
|
+
import { currentPage } from "./pages";
|
|
12
13
|
export type StepPhase =
|
|
13
14
|
/** Looking for the target (dim page, "กำลังโหลด…"). */
|
|
14
15
|
"waiting"
|
|
@@ -47,6 +48,21 @@ export type GuideScreen = {
|
|
|
47
48
|
/** A commit step shown in its read form: nothing to save
|
|
48
49
|
* (GuideStep.nothingToSave). */
|
|
49
50
|
nothingToSave: boolean;
|
|
51
|
+
/** The step's status line now (GuideStep.status), or null. */
|
|
52
|
+
status: string | null;
|
|
53
|
+
/**
|
|
54
|
+
* A replay's "select" step offers ถัดไป: what comes next is already on
|
|
55
|
+
* the page (the save button of a form that holds a value), so a review
|
|
56
|
+
* need not change a real record to go on. Shell ≥ 0.1.73.
|
|
57
|
+
*/
|
|
58
|
+
replayNext: boolean;
|
|
59
|
+
/** A page guide's step: the page key (the mission is `page:<key>`). Shell ≥ 0.1.74. */
|
|
60
|
+
page?: string;
|
|
61
|
+
}
|
|
62
|
+
/** The first-visit offer of this page's guide: a small card, not modal. */
|
|
63
|
+
| {
|
|
64
|
+
name: "pageOffer";
|
|
65
|
+
page: string;
|
|
50
66
|
} | {
|
|
51
67
|
name: "celebrate";
|
|
52
68
|
mission: string;
|
|
@@ -76,6 +92,29 @@ export interface GuideState {
|
|
|
76
92
|
* the next idle moment (never mid-step). Not saved: a reload drops it.
|
|
77
93
|
*/
|
|
78
94
|
pendingCelebrate: string[];
|
|
95
|
+
/** Who gets page guides ("optional" for every member while they are on). */
|
|
96
|
+
pageAudience: GuideAudience;
|
|
97
|
+
/** How page guides are offered: off, from "?" only, or also on a first visit. */
|
|
98
|
+
pagesMode: PagesMode;
|
|
99
|
+
/** Page rows by page key, as the server holds them (or as just written). */
|
|
100
|
+
pages: Record<string, PageRow>;
|
|
101
|
+
/**
|
|
102
|
+
* The page guide being played: `write` when its row is still to be
|
|
103
|
+
* written (the offer was taken, or this person has never ended this
|
|
104
|
+
* version); a replay from "?" of a recorded page writes nothing.
|
|
105
|
+
*/
|
|
106
|
+
pageRun: {
|
|
107
|
+
key: string;
|
|
108
|
+
write: boolean;
|
|
109
|
+
} | null;
|
|
110
|
+
/** What the panel shows: everything, or the page guides alone ("คู่มือทุกหน้า"). */
|
|
111
|
+
panelSection: "all" | "pages";
|
|
112
|
+
}
|
|
113
|
+
/** The page-guide part of the state, from the progress answer. */
|
|
114
|
+
export interface GuidePagesInit {
|
|
115
|
+
pageAudience: GuideAudience;
|
|
116
|
+
pagesMode: PagesMode;
|
|
117
|
+
pages: Record<string, PageRow>;
|
|
79
118
|
}
|
|
80
119
|
export interface ReplayPage {
|
|
81
120
|
mission: string;
|
|
@@ -182,6 +221,7 @@ export type GuideAction = {
|
|
|
182
221
|
type: "dismissComplete";
|
|
183
222
|
} | {
|
|
184
223
|
type: "openPanel";
|
|
224
|
+
section?: "all" | "pages";
|
|
185
225
|
} | {
|
|
186
226
|
type: "closePanel";
|
|
187
227
|
} | {
|
|
@@ -201,6 +241,34 @@ export type GuideAction = {
|
|
|
201
241
|
/** The host is idle: show a waiting `completeOn` celebration. */
|
|
202
242
|
| {
|
|
203
243
|
type: "idleCelebrate";
|
|
244
|
+
}
|
|
245
|
+
/** The host found this page's guide due (pageOfferDue): show the offer card. */
|
|
246
|
+
| {
|
|
247
|
+
type: "pageOffer";
|
|
248
|
+
page: string;
|
|
249
|
+
}
|
|
250
|
+
/** The offer's [เริ่ม]. */
|
|
251
|
+
| {
|
|
252
|
+
type: "pageOfferStart";
|
|
253
|
+
}
|
|
254
|
+
/** The offer's [ไม่ตอนนี้]: recorded, never offered again (this version). */
|
|
255
|
+
| {
|
|
256
|
+
type: "pageOfferLater";
|
|
257
|
+
}
|
|
258
|
+
/** "คู่มือหน้านี้" from "?", or a page in the panel's list (once on its page). */
|
|
259
|
+
| {
|
|
260
|
+
type: "startPage";
|
|
261
|
+
page: string;
|
|
262
|
+
}
|
|
263
|
+
/** ย้อนกลับ on a page guide's read step. */
|
|
264
|
+
| {
|
|
265
|
+
type: "back";
|
|
266
|
+
}
|
|
267
|
+
/** A page row came back from the server. */
|
|
268
|
+
| {
|
|
269
|
+
type: "pageRow";
|
|
270
|
+
key: string;
|
|
271
|
+
row: PageRow;
|
|
204
272
|
};
|
|
205
273
|
export type GuideEffect = {
|
|
206
274
|
type: "save";
|
|
@@ -222,6 +290,13 @@ export type GuideEffect = {
|
|
|
222
290
|
| {
|
|
223
291
|
type: "abort";
|
|
224
292
|
actions: GuideAbortAction[];
|
|
293
|
+
}
|
|
294
|
+
/** Write a page guide's row, once: `<app>.page.<key>`. */
|
|
295
|
+
| {
|
|
296
|
+
type: "savePage";
|
|
297
|
+
key: string;
|
|
298
|
+
version: number;
|
|
299
|
+
status: "completed" | "skipped";
|
|
225
300
|
};
|
|
226
301
|
export interface GuideResult {
|
|
227
302
|
state: GuideState;
|
|
@@ -236,11 +311,12 @@ export declare const COPY: {
|
|
|
236
311
|
readonly replayEnded: "จบการทบทวนแล้ว";
|
|
237
312
|
readonly hiddenToast: "ซ่อนแล้ว";
|
|
238
313
|
readonly aborted: "ไกด์ไปต่อไม่ได้ ลองอีกครั้งภายหลัง";
|
|
314
|
+
readonly pageDone: "จบคู่มือหน้านี้";
|
|
239
315
|
readonly bridgeTitle: "กดปุ่มเมนู";
|
|
240
316
|
readonly bridgeWhy: (app: string) => string;
|
|
241
317
|
};
|
|
242
318
|
export declare const BRIDGE_TARGET = "shell.menu-toggle";
|
|
243
|
-
export declare function initialGuideState(audience: GuideAudience, progress: GuideProgress): GuideState;
|
|
319
|
+
export declare function initialGuideState(audience: GuideAudience, progress: GuideProgress, pages?: GuidePagesInit): GuideState;
|
|
244
320
|
export declare function findMission(suite: GuideSuite, key: string | null | undefined): GuideMission | undefined;
|
|
245
321
|
/**
|
|
246
322
|
* Whether the user has this mission (GuideMission.visible). Without the
|
|
@@ -319,10 +395,50 @@ export declare function stepPosition(mission: GuideMission, index: number, env:
|
|
|
319
395
|
};
|
|
320
396
|
/** "กด [บันทึก]" → "กด บันทึก" (for screen readers). */
|
|
321
397
|
export declare function plainTitle(t: string): string;
|
|
398
|
+
/** The step's status line (GuideStep.status): trimmed text, or null. */
|
|
399
|
+
export declare function stepStatus(step: GuideStep, ctx: GuideContext): string | null;
|
|
400
|
+
/**
|
|
401
|
+
* In a replay, whether a "select" step may go on with ถัดไป: the next step
|
|
402
|
+
* this person sees has its target on the page already (or there is none).
|
|
403
|
+
* A pick that makes the next step's target (a save shown only once the
|
|
404
|
+
* right value is chosen) is still needed.
|
|
405
|
+
*/
|
|
406
|
+
export declare function replayCanGoOn(mission: GuideMission, index: number, env: GuideEnv, context: Readonly<Record<string, string>>, nothingToSave?: boolean): boolean;
|
|
322
407
|
/** A mission's `completeOn` triggers, as a list. */
|
|
323
408
|
export declare function completeTriggersOf(mission: GuideMission): GuideTrigger[];
|
|
324
409
|
/** Every app event name a suite's `completeOn` listens for. */
|
|
325
410
|
export declare function passiveEventNames(suite: GuideSuite): string[];
|
|
326
411
|
/** Missions whose `completeOn` this signal meets ({ api } and { event } only). */
|
|
327
412
|
export declare function passiveMatches(suite: GuideSuite, sig: GuideSignal): GuideMission[];
|
|
413
|
+
/** This page's guide for this person (the most specific match, if theirs). */
|
|
414
|
+
export declare function pageHere(suite: GuideSuite, env: GuideEnv): ReturnType<typeof currentPage>;
|
|
415
|
+
/** The page guide's row says this person has ended this version of it. */
|
|
416
|
+
export declare function pageRecorded(state: GuideState, page: {
|
|
417
|
+
key: string;
|
|
418
|
+
version: number;
|
|
419
|
+
}): boolean;
|
|
420
|
+
/** Whether the first step this person sees has its target on screen (or none). */
|
|
421
|
+
export declare function firstStepReady(suite: GuideSuite, pageKey: string, env: GuideEnv): boolean;
|
|
422
|
+
/**
|
|
423
|
+
* The page guide to offer now, or null. Due when: pages mode is "offer" and
|
|
424
|
+
* this person has page guides; nothing else is up (no step, card, panel or
|
|
425
|
+
* celebration waiting); this page's guide is theirs, may be offered, and has
|
|
426
|
+
* no row of this version; its first step's target is on screen; no app
|
|
427
|
+
* dialog is open. The host adds the rest: the welcome not due on this
|
|
428
|
+
* route, a moment of nothing loading, the primary tab, not hidden.
|
|
429
|
+
*/
|
|
430
|
+
export declare function pageOfferDue(state: GuideState, suite: GuideSuite, env: GuideEnv): string | null;
|
|
431
|
+
/** The step before this one that this person sees, or -1. */
|
|
432
|
+
export declare function previousShownIndex(mission: GuideMission, index: number, env: GuideEnv, context: Readonly<Record<string, string>>): number;
|
|
433
|
+
/**
|
|
434
|
+
* Where ย้อนกลับ goes from a page guide's step, or null. The step before it
|
|
435
|
+
* that this person sees; from inside what a click opened (not a
|
|
436
|
+
* checkpoint) back to that click, closing it first (the step's abort,
|
|
437
|
+
* Escape by default). A click step whose result is still on screen (a tab
|
|
438
|
+
* switched) is passed over: entering it again would pass it at once.
|
|
439
|
+
*/
|
|
440
|
+
export declare function backTarget(mission: GuideMission, index: number, env: GuideEnv, context: Readonly<Record<string, string>>): {
|
|
441
|
+
index: number;
|
|
442
|
+
close: boolean;
|
|
443
|
+
} | null;
|
|
328
444
|
export declare function reduceGuide(state: GuideState, action: GuideAction, suite: GuideSuite, env: GuideEnv): GuideResult;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page guides ("คู่มือหน้านี้", shell 0.1.74): which page guides a suite
|
|
3
|
+
* really has (validation), which one is this page's (the most specific
|
|
4
|
+
* match), and how one runs as a mission. Pure: the tests run it in Node.
|
|
5
|
+
*
|
|
6
|
+
* A page guide runs through the missions' machinery as a synthetic mission
|
|
7
|
+
* `page:<key>` in replay mode, so nothing it does writes tour progress.
|
|
8
|
+
*/
|
|
9
|
+
import type { GuideContext, GuideMission, GuidePage, GuideSuite } from "./types";
|
|
10
|
+
/** The synthetic mission key of a page guide: `page:<key>`. */
|
|
11
|
+
export declare const PAGE_PREFIX = "page:";
|
|
12
|
+
export declare function isPageMissionKey(key: string | null | undefined): boolean;
|
|
13
|
+
export declare function pageKeyOf(missionKey: string | null | undefined): string | undefined;
|
|
14
|
+
/** Why a page guide cannot run, or null when it can. */
|
|
15
|
+
export declare function pageProblem(app: string, page: GuidePage): string | null;
|
|
16
|
+
/**
|
|
17
|
+
* The suite's page guides that can run. A page guide with a commit, input or
|
|
18
|
+
* select step (it would save), a bad key or no route is dropped, with a
|
|
19
|
+
* warning in development; so is a second one with the same key.
|
|
20
|
+
*/
|
|
21
|
+
export declare function validPages(suite: GuideSuite): GuidePage[];
|
|
22
|
+
export declare function findPage(suite: GuideSuite, key: string | null | undefined): GuidePage | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* The page guide as a mission the machine plays: `page:<key>`. Steps lose
|
|
25
|
+
* any `route` (the guide is the page's, and ends when it is left) and are
|
|
26
|
+
* checkpoints unless they say otherwise.
|
|
27
|
+
*/
|
|
28
|
+
export declare function pageMission(page: GuidePage): GuideMission;
|
|
29
|
+
/** What the page matching needs to know about where the person is. */
|
|
30
|
+
export interface PageWhere {
|
|
31
|
+
code: string;
|
|
32
|
+
pathname: string;
|
|
33
|
+
search: URLSearchParams;
|
|
34
|
+
isVisible: (anchor: string) => boolean;
|
|
35
|
+
}
|
|
36
|
+
/** How specific a route pattern is: its `?k=v` constraints, then its static segments. */
|
|
37
|
+
export declare function routeSpecificity(pattern: string): [number, number];
|
|
38
|
+
/**
|
|
39
|
+
* Whether the page guide applies here: one of its routes matches and its
|
|
40
|
+
* `when` anchor (if any) is on screen. The score ranks matches: `when`
|
|
41
|
+
* first, then query constraints, then static segments. Null when it does
|
|
42
|
+
* not apply.
|
|
43
|
+
*/
|
|
44
|
+
export declare function pageMatchScore(page: GuidePage, where: PageWhere): [number, number, number] | null;
|
|
45
|
+
/** The most specific page guide that applies here, whoever it is for (first in the list on a tie). */
|
|
46
|
+
export declare function matchingPage(suite: GuideSuite, where: PageWhere): GuidePage | null;
|
|
47
|
+
/** Whether this person has the page guide: `visible` (only true) and `requires`. */
|
|
48
|
+
export declare function pageShown(page: GuidePage, ctx: GuideContext): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* This page's guide for this person: the most specific match, when it is
|
|
51
|
+
* theirs. A more specific guide they do not have is not replaced by a less
|
|
52
|
+
* specific one (it would describe what is not on screen).
|
|
53
|
+
*/
|
|
54
|
+
export declare function currentPage(suite: GuideSuite, where: PageWhere, ctx: GuideContext): GuidePage | null;
|
|
55
|
+
/** The page guides this person has, for the panel's list (those with an `href`). */
|
|
56
|
+
export declare function listedPages(suite: GuideSuite, ctx: GuideContext): GuidePage[];
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* No runtime imports beyond sibling pure modules: the tests run it in Node.
|
|
9
9
|
*/
|
|
10
10
|
import type { GuideSuite } from "./types";
|
|
11
|
-
import { type GuideProgress, type GuidesAnswer } from "./progress";
|
|
11
|
+
import { type GuideProgress, type GuidesAnswer, type PageRow } from "./progress";
|
|
12
12
|
/** What a progress call is about. */
|
|
13
13
|
export interface GuideProgressRequest {
|
|
14
14
|
/** The suite's app ("peoplx", "liff"). */
|
|
@@ -66,3 +66,11 @@ export declare function loadGuides(adapter: GuideProgressAdapter, suite: GuideSu
|
|
|
66
66
|
* stored row, or null when it could not be saved.
|
|
67
67
|
*/
|
|
68
68
|
export declare function storeGuides(adapter: GuideProgressAdapter, suite: GuideSuite, progress: GuideProgress): Promise<GuideProgress | null>;
|
|
69
|
+
/**
|
|
70
|
+
* Writes a page guide's row (`<app>.page.<key>`) once: the minimal body,
|
|
71
|
+
* with the same 409 handling as the tour's row. Another tab that already
|
|
72
|
+
* recorded this version wins (its row is returned, nothing is sent again);
|
|
73
|
+
* an older version's row is replaced with its rev; a newer one stops. Returns
|
|
74
|
+
* the stored row, or null when it could not be saved.
|
|
75
|
+
*/
|
|
76
|
+
export declare function storePageRow(adapter: GuideProgressAdapter, app: string, key: string, version: number, status: "completed" | "skipped", rev: number): Promise<PageRow | null>;
|
package/dist/guide/progress.d.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* No runtime imports: the tests run this file in Node as it is.
|
|
7
7
|
*/
|
|
8
8
|
export type GuideMode = "off" | "invite" | "forced";
|
|
9
|
+
/** How page guides are offered (`guides.<app>.pages`): off, from "?" only, or also on a first visit. */
|
|
10
|
+
export type PagesMode = "off" | "menu" | "offer";
|
|
9
11
|
export type GuideAudience = "forced" | "optional" | "none";
|
|
10
12
|
export type GuideRowStatus = "in_progress" | "completed" | "skipped" | "aborted";
|
|
11
13
|
export type MissionStatus = "todo" | "active" | "done" | "skipped";
|
|
@@ -38,9 +40,21 @@ export interface GuideProgress {
|
|
|
38
40
|
/** The status the server holds (to know when a PUT needs restart: true). */
|
|
39
41
|
server_status: GuideRowStatus | null;
|
|
40
42
|
}
|
|
43
|
+
/** A page guide's row (`<app>.page.<key>`), as the client keeps it. */
|
|
44
|
+
export interface PageRow {
|
|
45
|
+
version: number;
|
|
46
|
+
status: GuideRowStatus;
|
|
47
|
+
rev: number;
|
|
48
|
+
}
|
|
41
49
|
export interface GuidesAnswer {
|
|
42
50
|
mode: GuideMode;
|
|
43
51
|
audience: GuideAudience;
|
|
52
|
+
/** The page guides' switch; "off" from an API without it. */
|
|
53
|
+
pagesMode: PagesMode;
|
|
54
|
+
/** Who gets page guides: "optional" for every member while pages are not off. */
|
|
55
|
+
pageAudience: GuideAudience;
|
|
56
|
+
/** Page rows by page key (the part after `<app>.page.`). */
|
|
57
|
+
pages: Record<string, PageRow>;
|
|
44
58
|
/** The suite's row; a fresh one when the user has none or an older version. */
|
|
45
59
|
progress: GuideProgress;
|
|
46
60
|
/** The server holds a newer version than this app's tour: do not run. */
|
|
@@ -58,6 +72,17 @@ export declare function parseGuidesAnswer(payload: unknown, suite: {
|
|
|
58
72
|
version: number;
|
|
59
73
|
app: string;
|
|
60
74
|
}): GuidesAnswer | null;
|
|
75
|
+
/** The row key of a page guide: `<app>.page.<key>`. */
|
|
76
|
+
export declare function pageRowKey(app: string, key: string): string;
|
|
77
|
+
/** Page rows among the list's rows, by page key. Off-shape rows are left out. */
|
|
78
|
+
export declare function parsePageRows(rows: unknown[], app: string): Record<string, PageRow>;
|
|
79
|
+
/** One page row (a list entry, a PUT answer, a 409's `current`); null when off-shape. */
|
|
80
|
+
export declare function parsePageRow(raw: unknown): PageRow | null;
|
|
81
|
+
/**
|
|
82
|
+
* A page row's PUT body: the least the server takes. Written once per page
|
|
83
|
+
* and version (finished: completed; not now, exited or left: skipped).
|
|
84
|
+
*/
|
|
85
|
+
export declare function pageBody(app: string, version: number, rev: number, status: "completed" | "skipped"): Record<string, unknown>;
|
|
61
86
|
/** The PUT body for the client's state. Drops keys the server would refuse. */
|
|
62
87
|
export declare function putBody(p: GuideProgress, app: string): Record<string, unknown>;
|
|
63
88
|
/**
|
package/dist/guide/types.d.ts
CHANGED
|
@@ -161,6 +161,14 @@ export interface GuideStep {
|
|
|
161
161
|
* `api.id` is the saved record's id (data.id or data.data.id).
|
|
162
162
|
*/
|
|
163
163
|
capture?: (e: GuideCaptureEvent, ctx: GuideContext) => Record<string, string> | void;
|
|
164
|
+
/**
|
|
165
|
+
* A short status line under the instruction while it returns text, e.g. a
|
|
166
|
+
* wrong pick on a "select" step: "ยังไม่ใช่ชื่อคุณ". A label of what is on
|
|
167
|
+
* the page now, not help text. Read again on every page change during the
|
|
168
|
+
* step (use `ctx.visible` on an anchor the page shows for that state).
|
|
169
|
+
* Shell ≥ 0.1.73.
|
|
170
|
+
*/
|
|
171
|
+
status?: (ctx: GuideContext) => string | null | undefined;
|
|
164
172
|
/** Skip the step (silently) when true. Runs every time it is entered. */
|
|
165
173
|
skipIf?: (ctx: GuideContext) => boolean;
|
|
166
174
|
/** A policy key the step needs (checked with `guides.can`); skipped when
|
|
@@ -314,6 +322,62 @@ export interface GuideGate {
|
|
|
314
322
|
/** The line on each mission in the panel while waiting: "ต้องมีพนักงาน 2 คน". */
|
|
315
323
|
pending: string;
|
|
316
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* A page guide ("คู่มือหน้านี้", shell ≥ 0.1.74): a read-only walk through one
|
|
327
|
+
* page's regions and buttons — what the page is for, what each column,
|
|
328
|
+
* filter and status means, what each button does. It never saves: only
|
|
329
|
+
* "view" and "click" steps (the engine drops a page guide with a "commit",
|
|
330
|
+
* "input" or "select" step, with a warning in development), and it runs as
|
|
331
|
+
* a replay, so nothing it touches writes tour progress. Authors:
|
|
332
|
+
* _claude-work/guides-r4/GUIDE-PAGES.md.
|
|
333
|
+
*
|
|
334
|
+
* Progress is one row per page per user, `<app>.page.<key>`, written once:
|
|
335
|
+
* when the first-visit offer is answered or ignored, or when the guide ends
|
|
336
|
+
* (finished → completed; exited or left → skipped). Opened again from "?",
|
|
337
|
+
* it writes nothing.
|
|
338
|
+
*/
|
|
339
|
+
export interface GuidePage {
|
|
340
|
+
/** Stable, [a-z0-9-]: the row key is `${suite.app}.page.${key}` (≤ 64 characters). */
|
|
341
|
+
key: string;
|
|
342
|
+
/** Raise it to offer this page's guide again to everyone (this page only). */
|
|
343
|
+
version: number;
|
|
344
|
+
/**
|
|
345
|
+
* The page, as GuideTrigger.route ("/[code]/project/budgets",
|
|
346
|
+
* "/[code]/project/detail/[id]?view=gantt"); several for one page. When
|
|
347
|
+
* several page guides match, the most specific wins: one with `when`, then
|
|
348
|
+
* the most `?k=v` constraints, then the most static segments. If the
|
|
349
|
+
* winner is not for this user (`visible`, `requires`), there is none here.
|
|
350
|
+
*/
|
|
351
|
+
route: string | string[];
|
|
352
|
+
/**
|
|
353
|
+
* An anchor that must be on screen for this guide to apply: sub-screens
|
|
354
|
+
* that share a URL (LIFF's leave list vs its form). The offer waits for it,
|
|
355
|
+
* and the guide ends when it goes.
|
|
356
|
+
*/
|
|
357
|
+
when?: GuideAnchorKey;
|
|
358
|
+
/** "งบประมาณ": the offer card, "?" → "คู่มือหน้านี้" and the panel's list. ≤ 30 characters. */
|
|
359
|
+
title: string;
|
|
360
|
+
/**
|
|
361
|
+
* Where the panel's "คู่มือแต่ละหน้า" list opens it (`[code]` filled in).
|
|
362
|
+
* Omit it for pages that need an id (`[id]`): those are listed only on
|
|
363
|
+
* the page itself, through "คู่มือหน้านี้".
|
|
364
|
+
*/
|
|
365
|
+
href?: GuideText;
|
|
366
|
+
/** Only `true` shows it (as GuideMission.visible): role, plan, module, menu. */
|
|
367
|
+
visible?: (ctx: GuideContext) => boolean | undefined;
|
|
368
|
+
/** A policy key the page needs (checked with `guides.can`). */
|
|
369
|
+
requires?: string;
|
|
370
|
+
/** false: never offered by itself, only opened from "?". Default true. */
|
|
371
|
+
offer?: boolean;
|
|
372
|
+
/**
|
|
373
|
+
* "view" and "click" steps only, ≤ 9 (the app's tests check the count).
|
|
374
|
+
* Steps take no `route`: the guide ends when the page is left. Every step
|
|
375
|
+
* is a checkpoint unless it says `checkpoint: false` (a step inside a
|
|
376
|
+
* dialog or menu a click opened: a closed dialog goes back to the click,
|
|
377
|
+
* and closing the guide there presses Escape).
|
|
378
|
+
*/
|
|
379
|
+
steps: GuideStep[];
|
|
380
|
+
}
|
|
317
381
|
/** One app's whole tour: the welcome, the missions, the finish. */
|
|
318
382
|
export interface GuideSuite {
|
|
319
383
|
/** Progress key on the server, "<app>.<name>": "peoplx.first-run". */
|
|
@@ -357,6 +421,8 @@ export interface GuideSuite {
|
|
|
357
421
|
};
|
|
358
422
|
};
|
|
359
423
|
missions: GuideMission[];
|
|
424
|
+
/** Page guides ("คู่มือหน้านี้"), shell ≥ 0.1.74. */
|
|
425
|
+
pages?: GuidePage[];
|
|
360
426
|
}
|
|
361
427
|
/** AppLayoutShell's `guides` prop. */
|
|
362
428
|
export interface GuideConfig {
|
|
@@ -370,4 +436,10 @@ export interface GuideConfig {
|
|
|
370
436
|
* Default true.
|
|
371
437
|
*/
|
|
372
438
|
ready?: boolean;
|
|
439
|
+
/**
|
|
440
|
+
* False holds the page guides alone; default: as `ready`. Lets pages run
|
|
441
|
+
* while the missions wait (Accounx's settings pages are open before
|
|
442
|
+
* `module.accounting` is known). Shell ≥ 0.1.74.
|
|
443
|
+
*/
|
|
444
|
+
pagesReady?: boolean;
|
|
373
445
|
}
|
package/dist/guide-core.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var guideRuntime = require('./chunks/guide-runtime-
|
|
4
|
+
var guideRuntime = require('./chunks/guide-runtime-YS2nUhwS.cjs');
|
|
5
5
|
require('react/jsx-runtime');
|
|
6
6
|
require('react');
|
|
7
7
|
require('react-dom');
|
|
@@ -18,12 +18,18 @@ exports.apiCallDetail = guideRuntime.apiCallDetail;
|
|
|
18
18
|
exports.emitGuideEvent = guideRuntime.emitGuideEvent;
|
|
19
19
|
exports.fillRoute = guideRuntime.fillRoute;
|
|
20
20
|
exports.guideAnchor = guideRuntime.guideAnchor;
|
|
21
|
+
exports.guideMenuItems = guideRuntime.guideMenuItems;
|
|
22
|
+
exports.guideMenuShown = guideRuntime.guideMenuShown;
|
|
21
23
|
exports.loadGuides = guideRuntime.loadGuides;
|
|
22
24
|
exports.matchApiPath = guideRuntime.matchApiPath;
|
|
23
25
|
exports.matchRoute = guideRuntime.matchRoute;
|
|
24
26
|
exports.openGuidePanel = guideRuntime.openGuidePanel;
|
|
27
|
+
exports.openPageGuide = guideRuntime.openPageGuide;
|
|
28
|
+
exports.openPagesPanel = guideRuntime.openPagesPanel;
|
|
25
29
|
exports.reportApiCall = guideRuntime.reportApiCall;
|
|
26
30
|
exports.reportApiEvent = guideRuntime.reportApiEvent;
|
|
27
31
|
exports.storeGuides = guideRuntime.storeGuides;
|
|
28
32
|
exports.useGuideEntry = guideRuntime.useGuideEntry;
|
|
33
|
+
exports.usePageGuideEntry = guideRuntime.usePageGuideEntry;
|
|
34
|
+
exports.usePageGuides = guideRuntime.usePageGuides;
|
|
29
35
|
//# sourceMappingURL=guide-core.cjs.map
|
package/dist/guide-core.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guide-core.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"guide-core.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|