無操作検知
stimeo--idle
一定時間操作が無ければ idle(任意で事前に prompt)、再操作で active を発火。
stimeo--idle コントローラは document 上のユーザー操作(mousemove / keydown / scroll など、加えてタブが可視に戻ったとき)を監視し、timeout ミリ秒のあいだ操作が無ければコントローラ要素に data-idle を付与して stimeo--idle:idle を発火します。任意の stimeo--idle:prompt を promptBefore ミリ秒前に発火でき、確定タイムアウト前に警告を出す設計(WCAG 2.2.1 を支援)を促します。操作があるたびタイマを張り直し、idle / prompt 中に再操作すると stimeo--idle:active を発火して data-idle を外します。操作は document に capture + passive で監視するため、非バブルの scroll もどこで起きても拾えます。挙動のみで警告 UI は描画せず(Dialog / Confirm と組む)、サーバセッションには触れません。タイマとリスナは disconnect(Turbo 遷移含む)で解除します。通常はルート要素に 1 つ置き、data-turbo-permanent で遷移をまたいで計測を継続します。
ページの操作を止めてください。3 秒で警告、6 秒で idle になります。マウスを動かすかキーを押すと active に戻ります。
<%# Idle / session-timeout demo: the controller watches document-level activity and,
after a short demo timeout, fires prompt -> idle; interacting again fires active.
Real apps use a ~15-minute timeout; this demo shortens it (6s, warning at 3s) so the
transitions are visible. The library ships no UI, so demo.js mirrors the events into
the status badge below (whose labels are owned here for i18n). %>
<div
class="idle-demo"
data-controller="stimeo--idle"
data-stimeo--idle-timeout-value="6000"
data-stimeo--idle-prompt-before-value="3000">
<p class="idle-demo__hint"><%= t("components.idle.demo.hint") %></p>
<p
class="idle-demo__status"
role="status"
aria-live="polite"
data-idle-demo-status
data-label-active="<%= t("components.idle.demo.active") %>"
data-label-prompt="<%= t("components.idle.demo.prompt") %>"
data-label-idle="<%= t("components.idle.demo.idle") %>"></p>
</div>
/*
* Presentation-only styles for the idle demo. The library only fires events and toggles
* data-idle; this CSS lays out the hint + status badge and colors the badge by the
* demo-state mirror that demo.js writes (active / prompt / idle).
*/
.idle-demo {
display: flex;
flex-direction: column;
gap: 0.75rem;
max-width: 28rem;
}
.idle-demo__hint {
margin: 0;
color: var(--color-text-muted);
}
.idle-demo__status {
margin: 0;
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
border-radius: 0.375rem;
font-weight: 600;
text-align: center;
}
.idle-demo[data-demo-state="prompt"] .idle-demo__status {
border-color: var(--amber-500);
background: var(--amber-50);
color: var(--amber-500);
}
.idle-demo[data-demo-state="idle"] .idle-demo__status {
border-color: var(--danger-500);
background: var(--danger-50);
color: var(--color-accent);
}
// Idle demo (consumer-side JS).
//
// A ~15-minute production timeout can't be shown in a catalog, so the markup uses a
// short timeout / prompt window. The controller fires prompt -> idle as the page sits
// untouched and active when you interact again; this JS only mirrors those events into
// a visible status badge (the library ships no UI of its own). The badge copy is read
// from data-label-* so it stays owned by the i18n'd ERB.
document.querySelectorAll(".idle-demo").forEach((root) => {
const badge = root.querySelector("[data-idle-demo-status]");
if (!badge) return;
const labels = {
active: badge.dataset.labelActive,
prompt: badge.dataset.labelPrompt,
idle: badge.dataset.labelIdle,
};
const show = (state) => {
root.dataset.demoState = state;
badge.textContent = labels[state];
};
show("active");
root.addEventListener("stimeo--idle:prompt", () => show("prompt"));
root.addEventListener("stimeo--idle:idle", () => show("idle"));
root.addEventListener("stimeo--idle:active", () => show("active"));
});
これらのスタイルは共通のデザイントークン(ライト/ダーク両対応)を使います。 共通スタイルも一緒にコピーし、ルート要素の data-theme を切り替えればダークになります。
このコンポーネントを動かすために HTML へ記述する data-* 属性です。ルート要素に下の data-controller を付け、その内側に各 target / value / action を配置します。
ルート要素に付与
data-controller="stimeo--idle"
値(Values)
| 名前 | 説明 | 属性 |
|---|---|---|
timeout
|
無操作とみなすまでのミリ秒(既定 900000)。 | data-stimeo--idle-timeout-value |
promptBefore
|
確定タイムアウトの何ミリ秒前に prompt を出すか(0=警告なし)。 |
data-stimeo--idle-prompt-before-value |
events
|
操作とみなしてタイマをリセットするイベント種別(passive 監視)。visibilitychange は常時監視。 |
data-stimeo--idle-events-value |
イベント
| 名前 | 説明 | イベント |
|---|---|---|
prompt
|
確定タイムアウトの promptBefore ミリ秒前に発火。detail.remaining(ミリ秒)を伴う。 |
stimeo--idle:prompt |
idle
|
timeout 到達時に発火。 | stimeo--idle:idle |
active
|
prompt / idle 後に再操作したとき発火。 | stimeo--idle:active |
状態フック
ライブラリが操作するのはこれらの ARIA / data 属性、カスタムプロパティだけです。見た目は利用側 CSS がこれらに反応して作ります([aria-selected] / [aria-expanded] / var(--stimeo--…) などのセレクタでフックします)。
| フック | 対象 | 意味 |
|---|---|---|
data-idle |
コントローラ要素 | idle 中に付与(値は true)。操作再開で除去。 |