@dennykuo/glass-toast 0.1.0 → 0.1.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,44 @@
1
+ # Changelog
2
+
3
+ ## 0.1.2 (2026-11-15)
4
+
5
+ ### Added
6
+
7
+ - Pass an open native `dialog` to show and announce a toast inside it. Closing the dialog clears its toasts.
8
+
9
+ ### Fixed
10
+
11
+ - Retry actions run once at a time. Async actions keep the toast open while pending and allow a retry after failure.
12
+ - Toast stacks scroll on short screens so older actions and close buttons remain reachable.
13
+ - Non-finite durations use the default, and large durations are capped at the browser timer limit.
14
+ - Calling `show()` without a DOM returns a no-op dismiss function.
15
+ - The default jsDelivr link serves a browser JavaScript file while CommonJS keeps its existing entry.
16
+
17
+ ### Changed
18
+
19
+ - Pages deploys after a clean install from npm and verifies the live docs, CDN examples, and demo after deployment.
20
+
21
+ ## 0.1.1 (2026-11-14)
22
+
23
+ ### Added
24
+
25
+ - Added a [Traditional Chinese documentation site](https://dennykuo.github.io/glass-toast/) and an [interactive demo](https://dennykuo.github.io/glass-toast/demo.html), with links from both READMEs.
26
+ - Added `register({ closeLabel })` to localize the close button's accessible name. The default is `Close`.
27
+
28
+ ### Fixed
29
+
30
+ - Closing a notification preserves focus when the user moves it elsewhere during the exit animation.
31
+ - Improved action button text contrast in dark mode and when hovering over an error action in light mode.
32
+ - Long action labels wrap on narrow screens, leaving room for the message and close button. The close icon is easier to see in light mode.
33
+ - Clearing or evicting notifications cancels their timers. Clearing all notifications restores focus to the trigger when focus was inside a toast and the trigger is still available.
34
+ - Screen reader messages update separate live regions while the visible buttons remain available for interaction.
35
+ - Added CommonJS type declarations for the main entry point so TypeScript can resolve types from both ESM and CommonJS.
36
+ - Added a declaration for the stylesheet entry so strict TypeScript projects can import it without a global CSS shim.
37
+
38
+ ### Changed
39
+
40
+ - The supported Node.js range for the package and development tools is now `^22.13.0 || >=24.0.0`.
41
+
42
+ ## 0.1.0 (2026-10-08)
43
+
44
+ - Initial stable npm release of the dependency-free toast library, with ESM and UMD builds, TypeScript declarations, and a standalone stylesheet.
package/README.md CHANGED
@@ -1,61 +1,70 @@
1
1
  # @dennykuo/glass-toast
2
2
 
3
- 毛玻璃質感的 toast 通知元件 — vanilla JS、零 runtime 相依、不需要 Tailwind 或任何框架,開箱即用。
3
+ **English** | [繁體中文](README.zh-TW.md)
4
4
 
5
- - 4 種變體(success / error / warning / info):彩色圖示藥丸 + 進場 glow ring 脈衝 + 倒數進度條
6
- - 3 個位置(top-right / bottom-right / bottom-center),各自獨立堆疊容器
7
- - 毛玻璃外殼(backdrop-filter + 多層陰影),dismiss 時堆疊平滑坍縮回流
8
- - hover **與鍵盤焦點**皆暫停自動消失(含進度條同步暫停);`Esc` 關閉聚焦中的 toast、關閉後焦點交還觸發者(WCAG 2.2.1)
9
- - 內建 dark 外觀(**深色毛玻璃 + 淺字**,保留玻璃身分、避免夜間眩光),自動命中 `prefers-color-scheme` / `[data-theme="dark"]` / `.dark` 三種慣例
10
- - `prefers-reduced-motion` 完整降級(純淡入、無位移、無 glow;倒數進度條保留,仍提供時間指示)
11
- - a11y:`role="status"`(一般)/ `role="alert"`(error)+ 對應 `aria-live`(error 為 assertive,其餘 polite),圖示對藥丸底達 ≥3:1 對比
12
- - 內嵌 `action` 按鈕(如「重試」);error 未指定時停留較久(10s),同位置最多同時 4 則、超量自動收合最舊
13
- - SPA 友善:容器與樣式在 body/head 被替換後自動重建(Astro ViewTransitions 實測)
5
+ [Documentation (繁體中文)](https://dennykuo.github.io/glass-toast/) · [Interactive demo](https://dennykuo.github.io/glass-toast/demo.html)
14
6
 
15
- ## 安裝
7
+ Glassmorphism toast notifications — vanilla JS, zero runtime dependencies, no Tailwind or framework required. Works out of the box.
8
+
9
+ - 4 variants (success / error / warning / info): colored icon pill, entrance glow-ring pulse, and a countdown progress bar
10
+ - 3 positions (top-right / bottom-right / bottom-center), each with its own stacking container
11
+ - Frosted-glass shell (`backdrop-filter` + layered shadows); the stack collapses smoothly when a toast is dismissed
12
+ - Auto-dismiss and the progress bar pause on hover and keyboard focus. Press `Esc` to close the focused toast.
13
+ - Built-in dark appearance (**dark frosted glass with light text** — keeps the glass look without a glaring white card at night), picked up automatically from `prefers-color-scheme`, `[data-theme="dark"]`, or `.dark`
14
+ - Full `prefers-reduced-motion` support (plain fade, no movement, no glow; the countdown bar stays because it conveys remaining time)
15
+ - Separate live regions announce regular messages as `status` and errors as `alert`. Localize the close button’s accessible name with `closeLabel`.
16
+ - Inline `action` button (e.g. "Retry"); errors stay longer by default (10 s); at most 4 toasts per position, the oldest one closes when a fifth arrives
17
+ - SPA-friendly: containers and styles are rebuilt automatically after `<body>` / `<head>` swaps (tested with Astro View Transitions)
18
+
19
+ ## Install
16
20
 
17
21
  ```bash
18
- npm install @dennykuo/glass-toast
22
+ npm install @dennykuo/glass-toast@0.1.2
19
23
  ```
20
24
 
21
- ## 快速開始
25
+ ## Quick start
22
26
 
23
- ### 1. side-effect 入口(最省事)
27
+ ### 1. Side-effect entry (simplest)
24
28
 
25
29
  ```js
26
30
  import '@dennykuo/glass-toast/auto';
27
31
 
28
- // 樣式已注入、window.toast 已掛載
29
- toast.success('儲存成功');
30
- toast.error('連線失敗', { position: 'bottom-center' });
32
+ // Styles are injected and window.toast is ready
33
+ toast.success('Saved');
34
+ toast.error('Connection failed', { position: 'bottom-center' });
31
35
  ```
32
36
 
33
- ### 2. 具名 import(可 tree-shake、不碰 window)
37
+ `/auto` is an ES module. CommonJS can load it with `require()` on supported Node versions (22.13+ within 22.x, or 24+). It sets up the global and injects styles when a browser DOM is present.
38
+
39
+ ### 2. Named imports (tree-shakable, no globals)
34
40
 
35
41
  ```js
36
42
  import { success, show } from '@dennykuo/glass-toast';
37
43
 
38
- success('儲存成功'); // 首次使用時自動注入樣式
39
- show('自訂', { type: 'warning', duration: 8000 });
44
+ success('Saved'); // styles are injected on first use
45
+ show('Custom', { type: 'warning', duration: 8000 });
40
46
  ```
41
47
 
42
- 搭配顯式樣式(正規做法,CSP / SSR 友善):
48
+ With an explicit stylesheet (recommended for CSP / SSR):
43
49
 
44
50
  ```js
45
51
  import '@dennykuo/glass-toast/style.css';
46
52
  import { register, success } from '@dennykuo/glass-toast';
47
53
 
48
- register({ global: false, injectStyles: false }); // 停用自動注入
49
- success('儲存成功');
54
+ register({ global: false, injectStyles: false }); // turn off auto-injection
55
+ success('Saved');
50
56
  ```
51
57
 
52
- ### 3. `<script>` 直接引入(UMD,全域 `GlassToast`)
58
+ ### 3. `<script>` tag (UMD, global `GlassToast`)
53
59
 
54
60
  ```html
55
- <script src="https://unpkg.com/@dennykuo/glass-toast"></script>
61
+ <script src="https://unpkg.com/@dennykuo/glass-toast@0.1.2"></script>
62
+ <!-- Or use jsDelivr
63
+ <script src="https://cdn.jsdelivr.net/npm/@dennykuo/glass-toast@0.1.2"></script>
64
+ -->
56
65
  <script>
57
- GlassToast.register(); // 掛 window.toast + 注入樣式
58
- toast.info('哈囉');
66
+ GlassToast.register(); // sets window.toast and injects styles
67
+ toast.info('Hello');
59
68
  </script>
60
69
  ```
61
70
 
@@ -63,101 +72,158 @@ success('儲存成功');
63
72
 
64
73
  ### `show(message, options?) => dismiss`
65
74
 
66
- 回傳手動關閉函式。快捷方法 `success` / `error` / `warning` / `info` 同簽名(省略 `type`)。
75
+ Returns a function that closes the toast. The shortcuts `success` / `error` / `warning` / `info` have the same signature (minus `type`).
67
76
 
68
- | option | 型別 | 預設 | 說明 |
77
+ | option | type | default | description |
69
78
  |---|---|---|---|
70
- | `type` | `'success' \| 'error' \| 'warning' \| 'info'` | `'info'` | 變體 |
71
- | `position` | `'top-right' \| 'bottom-right' \| 'bottom-center'` | `'top-right'` | 顯示位置 |
72
- | `persistent` | `boolean` | `false` | `true` 時不自動消失、無進度條 |
73
- | `duration` | `number` | `error` 為 `10000`、其餘 `5500` | 自動消失毫秒數;`≤ 0` 視為 `persistent` |
74
- | `action` | `{ label, onClick }` | — | 內嵌操作按鈕;點擊執行 `onClick` 後自動關閉。未顯式給 `duration` 時預設 `persistent`(需使用者操作) |
79
+ | `type` | `'success' \| 'error' \| 'warning' \| 'info'` | `'info'` | Variant |
80
+ | `position` | `'top-right' \| 'bottom-right' \| 'bottom-center'` | `'top-right'` | Where the toast appears |
81
+ | `persistent` | `boolean` | `false` | When `true`, the toast never auto-dismisses and shows no progress bar |
82
+ | `duration` | `number` | `10000` for `error`, `5500` otherwise | Non-finite values use the default. Finite values ≤ 0 mean `persistent`. Positive values are capped at 2,147,483,647 ms. |
83
+ | `action` | `{ label, onClick }` | — | Runs once at a time and closes the toast on success. Without an explicit finite `duration`, action toasts are persistent. |
84
+ | `dialog` | `HTMLDialogElement` | — | Shows and announces the toast inside an open native dialog. Closing the dialog clears its toasts. |
75
85
 
76
- 訊息走 `textContent`,不解析 HTML,塞什麼字串都安全(`action.label` 亦然)。
86
+ Messages are written with `textContent` and never parsed as HTML, so any string is safe (`action.label` too).
77
87
 
78
88
  ```js
79
89
  import { error } from '@dennykuo/glass-toast';
80
90
 
81
- error('上傳失敗,是否重試?', {
82
- action: { label: '重試', onClick: () => retryUpload() },
91
+ error('Upload failed. Retry?', {
92
+ action: { label: 'Retry', onClick: () => retryUpload() },
83
93
  });
84
94
  ```
85
95
 
96
+ Return the Promise from `onClick` to pause the countdown until the request settles. If the callback throws or rejects, the library logs the error and lets the user retry. Handle any user-facing error details in your application.
97
+
98
+ On short screens, scroll the stack to reach older toasts. Tabbing to a button brings it into view.
99
+
86
100
  ### `dismissAll(options?)`
87
101
 
88
- 清空所有 toast。**預設只清空、不影響後續 `show()`**。若要鎖住後續 toast(供「session 過期 → 硬導航登入頁」情境,避免 redirect 與 unload 之間閃現新 toast)傳 `{ suppress: true }`;整頁重載後自動解鎖,SPA 不重載時用 `resume()` 解鎖:
102
+ Clears every toast. **By default it only clears; later `show()` calls work as usual.** Pass `{ suppress: true }` to also block later toasts — useful when a session expires and you hard-navigate to the login page, so nothing flashes between the redirect and unload. A full page reload unblocks automatically; in an SPA without a reload, call `resume()`:
89
103
 
90
104
  ```js
91
- dismissAll(); // 只清空(預設)
92
- dismissAll({ suppress: true }); // 清空並鎖住後續 show()(硬導航前)
93
- resume(); // SPA 不重載時手動解鎖
105
+ dismissAll(); // clear only (default)
106
+ dismissAll({ suppress: true }); // clear and block later show() calls (before a hard navigation)
107
+ resume(); // unblock manually in an SPA
94
108
  ```
95
109
 
96
110
  ### `register(options?) => api`
97
111
 
98
- 掛載全域 + 注入樣式(`/auto` 入口等價於無參數呼叫本函式)。
112
+ Sets up the global and injects styles (the `/auto` entry is the same as calling this with no options).
99
113
 
100
- | option | 預設 | 說明 |
114
+ | option | default | description |
101
115
  |---|---|---|
102
- | `global` | `true` | 掛 `target.toast` |
103
- | `injectStyles` | `true` | `false` 時全面停用自動樣式注入 |
104
- | `target` | `window` | 全域掛載目標 |
116
+ | `global` | `true` | Assign the API to `target.toast` |
117
+ | `injectStyles` | `true` | `false` turns off automatic style injection entirely |
118
+ | `target` | `window` | Object that receives the global |
119
+ | `closeLabel` | `'Close'` | The close button's `aria-label`; set it to your UI language, e.g. `register({ closeLabel: 'Schließen' })` |
105
120
 
106
121
  ### `ensureStyles()`
107
122
 
108
- 冪等注入樣式(`show()` 每次都會 cheap re-check,SPA 換頁把 `<head>` 注入的樣式拔掉也會自我修復)。SSR(無 `document`)為 no-op。
123
+ Injects the styles idempotently. `show()` does a cheap re-check every time, so it also recovers if an SPA navigation removes the injected `<style>` from `<head>`. No-op during SSR (no `document`).
109
124
 
110
- ## 樣式客製(CSS 變數)
125
+ ## Theming (CSS variables)
111
126
 
112
- 所有顏色走 `--gt-*` custom properties,scope 在 `.glass-toast` 上、不污染 `:root`。在你的 stylesheet 覆蓋即可:
127
+ All colors go through `--gt-*` custom properties scoped to `.glass-toast`, so nothing leaks onto `:root`. Override them in your own stylesheet:
113
128
 
114
129
  ```css
115
130
  .glass-toast { --gt-text: #333; --gt-radius: 0.5rem; }
116
131
  .glass-toast--success { --gt-icon: #0a7d4f; --gt-ring: 10, 125, 79; }
117
132
  ```
118
133
 
119
- | 變數 | 預設(light) | 說明 |
134
+ | variable | default (light) | description |
120
135
  |---|---|---|
121
- | `--gt-bg` | `rgba(255,255,255,.8)` | 外殼底色 |
122
- | `--gt-bg-opaque` | `rgba(255,255,255,.96)` | backdrop-filter 不支援時的後備底色 |
123
- | `--gt-border` | `rgba(229,231,235,.4)` | 外殼邊線 |
124
- | `--gt-text` | `#4a5565` | 訊息文字 |
125
- | `--gt-blur` | `24px` | 毛玻璃模糊半徑 |
126
- | `--gt-radius` | `1rem` | 外殼圓角 |
127
- | `--gt-shadow` | 多層陰影 | 外殼陰影(glow ring 疊加其上) |
128
- | `--gt-close-*` | gray 系 | 關閉鈕 bg / border / text(含 `-hover`) |
129
- | `--gt-focus-ring` | `#2563eb`(dark `#93c5fd`) | 關閉鈕 / action 鈕 focus-visible ring |
130
- | `--gt-action-*` | 承變體色 | action 鈕 bg / border / text(含 `-bg-hover`);預設透明底 + 變體色字 |
131
- | `--gt-pill-bg` / `--gt-icon` / `--gt-bar` | 依變體 | 圖示藥丸底 / 圖示色 / 進度條色 |
132
- | `--gt-ring` | 依變體 | glow ring 的 `R, G, B` 三元組(餵給 `el.animate()`) |
136
+ | `--gt-bg` | `rgba(255,255,255,.8)` | Shell background |
137
+ | `--gt-bg-opaque` | `rgba(255,255,255,.96)` | Fallback background when `backdrop-filter` is unsupported |
138
+ | `--gt-border` | `rgba(229,231,235,.4)` | Shell border |
139
+ | `--gt-text` | `#4a5565` | Message text |
140
+ | `--gt-blur` | `24px` | Frosted-glass blur radius |
141
+ | `--gt-radius` | `1rem` | Shell corner radius |
142
+ | `--gt-shadow` | layered shadow | Shell shadow (the glow ring is drawn on top) |
143
+ | `--gt-close-*` | grays | Close button bg / border / text (plus `-hover` versions) |
144
+ | `--gt-focus-ring` | `#2563eb` (dark: `#93c5fd`) | Focus-visible ring for the close and action buttons |
145
+ | `--gt-action-*` | follows the appearance | Action button bg / border / text (plus `-bg-hover`); light mode uses variant-colored text (error uses red-700), dark mode uses message text and a neutral hover background |
146
+ | `--gt-pill-bg` / `--gt-icon` / `--gt-bar` | per variant | Icon pill / icon color / progress bar |
147
+ | `--gt-ring` | per variant | Glow-ring color as an `R, G, B` triplet (fed to `el.animate()`) |
133
148
 
134
- ### Dark 外觀
149
+ ### Dark appearance
135
150
 
136
- dark 為**深色毛玻璃**(低亮度半透明底 `rgba(28,28,30,.72)` + 淺字),保留玻璃身分、避免夜間白卡眩光;變體藥丸/圖示沿用 base(淺色亮片 + 700 階圖示在深底上仍清晰),只覆寫外殼、關閉鈕與 focus ring。
151
+ Dark mode is **dark frosted glass** (a low-luminance translucent background, `rgba(28,28,30,.72)`, with light text) — it keeps the glass look without a glaring white card at night. Variant pills and icons reuse the light values. The shell, close button and focus ring are overridden; action buttons use the message text color and a neutral hover background so small text stays legible.
137
152
 
138
- 以下三種慣例任一成立即套用(頁面明示 `data-theme="light"` / `.light` 時 OS 深色讓路):
153
+ It applies when any of these is true (an explicit `data-theme="light"` or `.light` on the page wins over the OS setting):
139
154
 
140
155
  1. `@media (prefers-color-scheme: dark)`
141
156
  2. `<html data-theme="dark">`
142
- 3. `<html class="dark">`(Tailwind 慣例)
157
+ 3. `<html class="dark">` (Tailwind convention)
158
+
159
+ All dark overrides use `:where()` to keep the same specificity as the base rules, so your overrides never have to fight the package's selectors.
143
160
 
144
- dark 覆寫全部走 `:where()` 壓成與 base 相同的 specificity,你的覆蓋規則永遠不需要跟套件比權重。
161
+ ## CSP / SSR notes
145
162
 
146
- ## CSP / SSR 註記
163
+ Use `persistent: true` for important messages or actions available only in the toast, or provide another way to access them after it closes. See [WCAG 2.2.1 Timing Adjustable](https://www.w3.org/WAI/WCAG22/Understanding/timing-adjustable.html).
147
164
 
148
- - 嚴格 CSP(禁 inline `<style>`):改顯式 `import '@dennykuo/glass-toast/style.css'` + `register({ injectStyles: false })`
149
- - 已自行載入 style.css 且想避免重複注入:在你的 `<link>` / `<style>` 加 `data-glass-toast` 屬性即可被偵測跳過
150
- - SSR:所有入口在無 `document` 環境安全 no-op,`show()` 請在 client 端呼叫
165
+ - Strict CSP (no inline `<style>`): import `'@dennykuo/glass-toast/style.css'` explicitly and call `register({ injectStyles: false })`
166
+ - Already loading the stylesheet yourself and want to avoid a duplicate: add a `data-glass-toast` attribute to your `<link>` / `<style>` and auto-injection will detect it and skip
167
+ - SSR: `show()` returns a no-op dismiss function when no DOM is available. Call it on the client to display a toast.
168
+
169
+ Pass the open `dialog` element to keep the toast and its controls inside a native modal. An unopened or detached dialog produces no toast.
170
+
171
+ ```js
172
+ import { error } from '@dennykuo/glass-toast';
173
+
174
+ const dialog = document.querySelector('#upload-dialog');
175
+ dialog.showModal();
176
+ error('Upload failed', { dialog, persistent: true });
177
+ ```
151
178
 
152
- ## 開發
179
+ ## Development
180
+
181
+ Use Node 24 (`nvm use`; CI reads `.nvmrc`). Node 22.13+ is also supported on the 22.x line.
153
182
 
154
183
  ```bash
155
- npm run dev # vite demo(互動 playground:四變體 × 三位置 × 深淺外觀 × 三種背景底圖)
156
- npm test # vitest + jsdom(58 tests)
157
- npm run lint # eslint
158
- npm run build # dist/:ESM + UMD + CSS + .d.ts
184
+ npm ci --ignore-scripts # install from the lockfile without dependency lifecycle scripts
185
+ npx playwright install chromium firefox webkit # one-time browser setup
186
+ npm run dev # docs site: / docs, /demo.html interactive playground
187
+ npm test # vitest + jsdom (includes documentation coverage guards)
188
+ npm run test:browser # Chromium, Firefox, and WebKit at desktop and mobile widths
189
+ npm run lint # ESLint, including docs scripts
190
+ npm run build # dist/: ESM + UMD + CSS + .d.ts / .d.cts
191
+ npm run check:package # lint the tarball and type-check the README examples against it
192
+ npm run build:docs # dist-docs/: static docs site (relative paths, ready for GitHub Pages)
193
+ ```
194
+
195
+ The docs site lives entirely in `docs/` (the site content is currently in Traditional Chinese):
196
+
197
+ ```
198
+ docs/
199
+ index.html Docs (home page)
200
+ demo.html Interactive playground
201
+ partials/ Shared HTML fragments, inserted at build time by vite.config.js
202
+ site.css Shared styles
203
+ index.js Docs page interactions
204
+ demo.js Demo page interactions
205
+ site.js Shared scripts
206
+ public/appearance.js Restores appearance before the page is painted
207
+ scrollspy.js Table-of-contents scroll sync (pure function, test/scrollspy.test.js)
208
+ vite.config.js Docs site config (picked up automatically by `vite docs`)
159
209
  ```
160
210
 
211
+ Pages sit flat in the `docs/` root, so links inside partials always use `./`. The package name and version come from `package.json` via `%PKG_NAME%` and friends.
212
+
213
+ CI checks pushes to `main` and `develop`, plus pull requests. On `main`, CI installs the exact public npm version into a fresh project before deploying the docs. If deployment is skipped because the version is unpublished, run **CI** on `main` after publishing. After deployment, CI opens the live docs and verifies the version, CDN scripts, and the demo retry action. CI also checks the version in both READMEs.
214
+
215
+ The development-only `minimatch` override selects v11 while ESLint still requests v10,
216
+ to address [GHSA-g3hv-75wg-m249](https://github.com/isaacs/minimatch/security/advisories/GHSA-g3hv-75wg-m249).
217
+ Its file selection, ignore patterns, and error reporting have been checked with this project.
218
+ Revisit the override when updating ESLint; remove it once upstream dependencies include the fix.
219
+
220
+ Documentation coverage is guarded by tests that scan the source for the public API, the `show()` / `register()` options, and every `--gt-*` variable:
221
+
222
+ - `test/docs.test.js` checks that `docs/index.html` has a matching `data-doc` entry for each
223
+ - `test/readme.test.js` checks that both `README.md` and `README.zh-TW.md` mention every export and option, and link to each other
224
+
225
+ When you add an API, update all of them.
226
+
161
227
  ## License
162
228
 
163
229
  MIT © Denny
@@ -0,0 +1,229 @@
1
+ # @dennykuo/glass-toast
2
+
3
+ [English](README.md) | **繁體中文**
4
+
5
+ [文件站](https://dennykuo.github.io/glass-toast/) · [互動 Demo](https://dennykuo.github.io/glass-toast/demo.html)
6
+
7
+ 毛玻璃質感的 toast 通知元件 — vanilla JS、零 runtime 相依、不需要 Tailwind 或任何框架,開箱即用。
8
+
9
+ - 4 種變體(success / error / warning / info):彩色圖示藥丸 + 進場 glow ring 脈衝 + 倒數進度條
10
+ - 3 個位置(top-right / bottom-right / bottom-center),各自獨立堆疊容器
11
+ - 毛玻璃外殼(backdrop-filter + 多層陰影),dismiss 時堆疊平滑坍縮回流
12
+ - 滑鼠移上或鍵盤焦點進入時暫停倒數,按 `Esc` 可關閉聚焦中的通知。
13
+ - 內建 dark 外觀(**深色毛玻璃 + 淺字**,保留玻璃身分、避免夜間眩光),自動命中 `prefers-color-scheme` / `[data-theme="dark"]` / `.dark` 三種慣例
14
+ - `prefers-reduced-motion` 完整降級(純淡入、無位移、無 glow;倒數進度條保留,仍提供時間指示)
15
+ - a11y:`role="status"`(一般)/ `role="alert"`(error)+ 對應 `aria-live`(error 為 assertive,其餘 polite),圖示對藥丸底達 ≥3:1 對比;關閉按鈕名稱可用 `closeLabel` 在地化
16
+ - 內嵌 `action` 按鈕(如「重試」);error 未指定時停留較久(10s),同位置最多同時 4 則、超量自動收合最舊
17
+ - SPA 友善:容器與樣式在 body/head 被替換後自動重建(Astro ViewTransitions 實測)
18
+
19
+ ## 安裝
20
+
21
+ ```bash
22
+ npm install @dennykuo/glass-toast@0.1.2
23
+ ```
24
+
25
+ ## 快速開始
26
+
27
+ ### 1. side-effect 入口(最省事)
28
+
29
+ ```js
30
+ import '@dennykuo/glass-toast/auto';
31
+
32
+ // 樣式已注入、window.toast 已掛載
33
+ toast.success('儲存成功');
34
+ toast.error('連線失敗', { position: 'bottom-center' });
35
+ ```
36
+
37
+ `/auto` 是 ES 模組。在支援的 Node 版本(22.x 自 22.13 起,或 24 以上),CommonJS 也可以用 `require()` 載入。有瀏覽器 DOM 時才會掛載全域與注入樣式。
38
+
39
+ ### 2. 具名 import(可 tree-shake、不碰 window)
40
+
41
+ ```js
42
+ import { success, show } from '@dennykuo/glass-toast';
43
+
44
+ success('儲存成功'); // 首次使用時自動注入樣式
45
+ show('自訂', { type: 'warning', duration: 8000 });
46
+ ```
47
+
48
+ 搭配顯式樣式(正規做法,CSP / SSR 友善):
49
+
50
+ ```js
51
+ import '@dennykuo/glass-toast/style.css';
52
+ import { register, success } from '@dennykuo/glass-toast';
53
+
54
+ register({ global: false, injectStyles: false }); // 停用自動注入
55
+ success('儲存成功');
56
+ ```
57
+
58
+ ### 3. `<script>` 直接引入(UMD,全域 `GlassToast`)
59
+
60
+ ```html
61
+ <script src="https://unpkg.com/@dennykuo/glass-toast@0.1.2"></script>
62
+ <!-- 也可以改用 jsDelivr
63
+ <script src="https://cdn.jsdelivr.net/npm/@dennykuo/glass-toast@0.1.2"></script>
64
+ -->
65
+ <script>
66
+ GlassToast.register(); // 掛 window.toast + 注入樣式
67
+ toast.info('哈囉');
68
+ </script>
69
+ ```
70
+
71
+ ## API
72
+
73
+ ### `show(message, options?) => dismiss`
74
+
75
+ 回傳手動關閉函式。快捷方法 `success` / `error` / `warning` / `info` 同簽名(省略 `type`)。
76
+
77
+ | option | 型別 | 預設 | 說明 |
78
+ |---|---|---|---|
79
+ | `type` | `'success' \| 'error' \| 'warning' \| 'info'` | `'info'` | 變體 |
80
+ | `position` | `'top-right' \| 'bottom-right' \| 'bottom-center'` | `'top-right'` | 顯示位置 |
81
+ | `persistent` | `boolean` | `false` | `true` 時不自動消失、無進度條 |
82
+ | `duration` | `number` | `error` 為 `10000`、其餘 `5500` | 非有限值使用預設。有指定有限值時,≤ 0 視為 `persistent`,正值上限為 2,147,483,647 毫秒。 |
83
+ | `action` | `{ label, onClick }` | — | 一次執行一個操作,成功後關閉。未指定有限的 `duration` 時,通知會持續顯示。 |
84
+ | `dialog` | `HTMLDialogElement` | — | 在已開啟的原生對話框內顯示與宣告通知。關閉對話框會清除其中的通知。 |
85
+
86
+ 訊息走 `textContent`,不解析 HTML,塞什麼字串都安全(`action.label` 亦然)。
87
+
88
+ ```js
89
+ import { error } from '@dennykuo/glass-toast';
90
+
91
+ error('上傳失敗,是否重試?', {
92
+ action: { label: '重試', onClick: () => retryUpload() },
93
+ });
94
+ ```
95
+
96
+ `onClick` 回傳 Promise 時,通知會暫停倒數,等操作成功才關閉。回呼拋錯或 Promise 被拒絕時,套件會把錯誤記到 console 並允許重試。應用程式可自行向使用者顯示失敗原因。
97
+
98
+ 短螢幕上可捲動堆疊查看較早的通知。使用 Tab 聚焦按鈕時,瀏覽器會將它捲入可見範圍。
99
+
100
+ ### `dismissAll(options?)`
101
+
102
+ 清空所有 toast。**預設只清空、不影響後續 `show()`**。若要鎖住後續 toast(供「session 過期 → 硬導航登入頁」情境,避免 redirect 與 unload 之間閃現新 toast)傳 `{ suppress: true }`;整頁重載後自動解鎖,SPA 不重載時用 `resume()` 解鎖:
103
+
104
+ ```js
105
+ dismissAll(); // 只清空(預設)
106
+ dismissAll({ suppress: true }); // 清空並鎖住後續 show()(硬導航前)
107
+ resume(); // SPA 不重載時手動解鎖
108
+ ```
109
+
110
+ ### `register(options?) => api`
111
+
112
+ 掛載全域 + 注入樣式(`/auto` 入口等價於無參數呼叫本函式)。
113
+
114
+ | option | 預設 | 說明 |
115
+ |---|---|---|
116
+ | `global` | `true` | 掛 `target.toast` |
117
+ | `injectStyles` | `true` | `false` 時全面停用自動樣式注入 |
118
+ | `target` | `window` | 全域掛載目標 |
119
+ | `closeLabel` | `'Close'` | 關閉按鈕的 `aria-label`;非英語介面請換成在地語言,例如 `register({ closeLabel: '關閉通知' })` |
120
+
121
+ ### `ensureStyles()`
122
+
123
+ 冪等注入樣式(`show()` 每次都會 cheap re-check,SPA 換頁把 `<head>` 注入的樣式拔掉也會自我修復)。SSR(無 `document`)為 no-op。
124
+
125
+ ## 樣式客製(CSS 變數)
126
+
127
+ 所有顏色走 `--gt-*` custom properties,scope 在 `.glass-toast` 上、不污染 `:root`。在你的 stylesheet 覆蓋即可:
128
+
129
+ ```css
130
+ .glass-toast { --gt-text: #333; --gt-radius: 0.5rem; }
131
+ .glass-toast--success { --gt-icon: #0a7d4f; --gt-ring: 10, 125, 79; }
132
+ ```
133
+
134
+ | 變數 | 預設(light) | 說明 |
135
+ |---|---|---|
136
+ | `--gt-bg` | `rgba(255,255,255,.8)` | 外殼底色 |
137
+ | `--gt-bg-opaque` | `rgba(255,255,255,.96)` | backdrop-filter 不支援時的後備底色 |
138
+ | `--gt-border` | `rgba(229,231,235,.4)` | 外殼邊線 |
139
+ | `--gt-text` | `#4a5565` | 訊息文字 |
140
+ | `--gt-blur` | `24px` | 毛玻璃模糊半徑 |
141
+ | `--gt-radius` | `1rem` | 外殼圓角 |
142
+ | `--gt-shadow` | 多層陰影 | 外殼陰影(glow ring 疊加其上) |
143
+ | `--gt-close-*` | gray 系 | 關閉鈕 bg / border / text(含 `-hover`) |
144
+ | `--gt-focus-ring` | `#2563eb`(dark `#93c5fd`) | 關閉鈕 / action 鈕 focus-visible ring |
145
+ | `--gt-action-*` | 隨外觀調整 | action 鈕 bg / border / text(含 `-bg-hover`);淺色使用變體文字色(error 為 red-700),深色使用訊息文字色與中性 hover 底色 |
146
+ | `--gt-pill-bg` / `--gt-icon` / `--gt-bar` | 依變體 | 圖示藥丸底 / 圖示色 / 進度條色 |
147
+ | `--gt-ring` | 依變體 | glow ring 的 `R, G, B` 三元組(餵給 `el.animate()`) |
148
+
149
+ ### Dark 外觀
150
+
151
+ dark 為**深色毛玻璃**(低亮度半透明底 `rgba(28,28,30,.72)` + 淺字),保留玻璃身分、避免夜間白卡眩光;變體藥丸/圖示沿用 base。除外殼、關閉鈕與 focus ring 外,action 改用訊息文字色與中性 hover 底色,維持小字的可讀性。
152
+
153
+ 以下三種慣例任一成立即套用(頁面明示 `data-theme="light"` / `.light` 時 OS 深色讓路):
154
+
155
+ 1. `@media (prefers-color-scheme: dark)`
156
+ 2. `<html data-theme="dark">`
157
+ 3. `<html class="dark">`(Tailwind 慣例)
158
+
159
+ dark 覆寫全部走 `:where()` 壓成與 base 相同的 specificity,你的覆蓋規則永遠不需要跟套件比權重。
160
+
161
+ ## CSP / SSR 註記
162
+
163
+ 若通知是取得重要訊息或執行操作的唯一方式,請使用 `persistent: true`,或另外提供可在通知關閉後使用的管道。參考 [WCAG 2.2.1 計時可調整](https://www.w3.org/WAI/WCAG22/Understanding/timing-adjustable.html)。
164
+
165
+ - 嚴格 CSP(禁 inline `<style>`):改顯式 `import '@dennykuo/glass-toast/style.css'` + `register({ injectStyles: false })`
166
+ - 已自行載入 style.css 且想避免重複注入:在你的 `<link>` / `<style>` 加 `data-glass-toast` 屬性即可被偵測跳過
167
+ - SSR:沒有 DOM 時,`show()` 回傳空的關閉函式。要顯示通知請在瀏覽器呼叫。
168
+
169
+ 使用原生 modal 時,可傳入已開啟的 `dialog`,讓通知和按鈕留在對話框內。傳入尚未開啟或已從頁面移除的對話框時,不會顯示通知。
170
+
171
+ ```js
172
+ import { error } from '@dennykuo/glass-toast';
173
+
174
+ const dialog = document.querySelector('#upload-dialog');
175
+ dialog.showModal();
176
+ error('上傳失敗', { dialog, persistent: true });
177
+ ```
178
+
179
+ ## 開發
180
+
181
+ 建議使用 Node 24(`nvm use`;CI 讀取 `.nvmrc`)。22.x 系列最低為 Node 22.13。
182
+
183
+ ```bash
184
+ npm ci --ignore-scripts # 依 lockfile 安裝,不執行依賴的生命週期腳本
185
+ npx playwright install chromium firefox webkit # 首次安裝瀏覽器
186
+ npm run dev # 文件站:/ 文件、/demo.html 互動 playground
187
+ npm test # vitest + jsdom(含文件覆蓋率守門)
188
+ npm run test:browser # Chromium、Firefox、WebKit,涵蓋桌機與手機寬度
189
+ npm run lint # ESLint,含文件站腳本
190
+ npm run build # dist/:ESM + UMD + CSS + .d.ts / .d.cts
191
+ npm run check:package # 檢查 tarball 並用乾淨安裝驗證 README 範例型別
192
+ npm run build:docs # dist-docs/:文件站靜態檔(相對路徑,可直接部署到 GitHub Pages)
193
+ ```
194
+
195
+ 文件站整個放在 `docs/`:
196
+
197
+ ```
198
+ docs/
199
+ index.html 文件(首頁)
200
+ demo.html 互動 playground
201
+ partials/ 共用 HTML 片段,由 vite.config.js 在建置時插入
202
+ site.css 共用樣式
203
+ index.js 文件首頁互動
204
+ demo.js Demo 互動
205
+ site.js 共用腳本
206
+ public/appearance.js 首次繪製前套用外觀
207
+ scrollspy.js 文件目錄的捲動同步判斷(純函式,test/scrollspy.test.js)
208
+ vite.config.js 文件站設定(vite docs 自動讀取)
209
+ ```
210
+
211
+ 頁面一律平放在 `docs/` 根目錄,partial 裡的站內連結都寫 `./`;套件名稱與版本以 `%PKG_NAME%` 等從 `package.json` 帶入。
212
+
213
+ CI 檢查 `main`、`develop` 的推送和 PR。`main` 會先在乾淨專案從公開 npm 安裝指定版本,再部署文件站。若因版本未發布而略過部署,發布後可在 `main` 手動執行 **CI**。部署完成後,CI 會打開正式站驗證版號、CDN 腳本和 Demo 的重試操作,並在檢查階段核對兩份 README 的版號。
214
+
215
+ 開發依賴暫以 `minimatch` override 選用 v11,處理 ESLint 仍要求 v10 時的
216
+ [GHSA-g3hv-75wg-m249](https://github.com/isaacs/minimatch/security/advisories/GHSA-g3hv-75wg-m249)。
217
+ 已核對本專案的檔案選取、忽略規則與錯誤偵測。後續更新 ESLint 時需重新檢查,
218
+ 待上游直接採用修補版後移除 override。
219
+
220
+ 文件覆蓋率由測試守門,從原始碼掃出公開 API、`show()` / `register()` 選項與所有 `--gt-*` 變數:
221
+
222
+ - `test/docs.test.js`:逐一確認 `docs/index.html` 有對應的 `data-doc` 條目
223
+ - `test/readme.test.js`:確認 `README.md`(英文)與 `README.zh-TW.md` 都提到每個 export 與選項,且互相連結
224
+
225
+ 新增 API 時記得每一份都要補。
226
+
227
+ ## License
228
+
229
+ MIT © Denny
@@ -0,0 +1 @@
1
+ export * from "./toast.cjs";
package/dist/auto.js CHANGED
@@ -1,5 +1,4 @@
1
- import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c } from "./toast-Bh3vjjkJ.js";
2
- //#region src/auto.js
1
+ import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c } from "./toast-GM0D-R2d.js";
2
+ // src/auto.js
3
3
  e();
4
- //#endregion
5
4
  export { c as dismissAll, i as ensureStyles, o as error, n as info, e as register, a as resume, s as show, t as success, r as warning };
@@ -1 +1 @@
1
- .glass-toast-container,.glass-toast,.glass-toast *{box-sizing:border-box}.glass-toast-container{z-index:2147483647;pointer-events:none;flex-direction:column;gap:.75rem;display:flex;position:fixed}.glass-toast-container--top-right{align-items:flex-end;top:1rem;right:1rem}.glass-toast-container--bottom-right{align-items:flex-end;bottom:1rem;right:1rem}.glass-toast-container--bottom-center{align-items:center;bottom:1rem;left:50%;transform:translate(-50%)}.glass-toast{--gt-bg:#fffc;--gt-bg-opaque:#fffffff5;--gt-border:#e5e7eb66;--gt-text:#4a5565;--gt-blur:24px;--gt-radius:1rem;--gt-shadow:0 4px 24px -4px #00000014, 0 1px 2px #0000000a;--gt-close-bg:#f9fafb;--gt-close-border:#e5e7eb;--gt-close-text:#99a1af;--gt-close-bg-hover:#f3f4f6;--gt-close-border-hover:#d1d5dc;--gt-close-text-hover:#4a5565;--gt-focus-ring:#2563eb;pointer-events:auto;background-color:var(--gt-bg);width:24rem;max-width:calc(100vw - 2rem);backdrop-filter:blur(var(--gt-blur));border:1px solid var(--gt-border);border-radius:var(--gt-radius);box-shadow:var(--gt-shadow);align-items:center;gap:.75rem;padding:.875rem 1rem;display:flex;position:relative;overflow:hidden}@supports not (backdrop-filter:blur(1px)){.glass-toast{background-color:var(--gt-bg-opaque)}}.glass-toast--success{--gt-pill-bg:#d0fae5;--gt-icon:#047857;--gt-bar:#00bb7f;--gt-ring:16, 185, 129}.glass-toast--error{--gt-pill-bg:#ffe2e2;--gt-icon:#dc2626;--gt-bar:#ff6568;--gt-ring:239, 68, 68}.glass-toast--warning{--gt-pill-bg:#fef3c6;--gt-icon:#b45309;--gt-bar:#fcbb00;--gt-ring:245, 158, 11}.glass-toast--info{--gt-pill-bg:#e2eaf1;--gt-icon:#3a5b7a;--gt-bar:#6f92ad;--gt-ring:76, 112, 144}.glass-toast--animated{transition:all .28s cubic-bezier(0,0,.2,1)}.glass-toast--leaving{transition-timing-function:cubic-bezier(.4,0,1,1)}.glass-toast--enter,.glass-toast--faded{opacity:0}.glass-toast--enter[data-position=top-right],.glass-toast--enter[data-position=bottom-right]{transform:translate(2rem)}.glass-toast--enter[data-position=bottom-center]{transform:translateY(2rem)}.glass-toast__icon{background-color:var(--gt-pill-bg);width:1.75rem;height:1.75rem;color:var(--gt-icon);border-radius:.5rem;flex-shrink:0;justify-content:center;align-items:center;display:flex}.glass-toast__icon svg{flex-shrink:0;width:18px;height:18px;display:block}.glass-toast__message{min-width:0;color:var(--gt-text);overflow-wrap:anywhere;-webkit-line-clamp:5;line-clamp:5;-webkit-box-orient:vertical;flex:1;margin:0;font-size:.9375rem;line-height:1.625;display:-webkit-box;overflow:hidden}.glass-toast__action{border:1px solid var(--gt-action-border,var(--gt-border));background-color:var(--gt-action-bg,transparent);color:var(--gt-action-text,var(--gt-icon));font:inherit;white-space:nowrap;cursor:pointer;appearance:none;border-radius:.5rem;flex-shrink:0;align-self:center;padding:.3125rem .75rem;font-size:.8125rem;font-weight:600;line-height:1;transition:background-color .15s cubic-bezier(.4,0,.2,1),border-color .15s cubic-bezier(.4,0,.2,1)}.glass-toast__action:hover{background-color:var(--gt-action-bg-hover,var(--gt-pill-bg))}.glass-toast__action:focus-visible{outline:2px solid var(--gt-focus-ring);outline-offset:2px}.glass-toast__close{border:1px solid var(--gt-close-border);background-color:var(--gt-close-bg);width:2rem;height:2rem;color:var(--gt-close-text);font:inherit;cursor:pointer;appearance:none;border-radius:9999px;flex-shrink:0;justify-content:center;align-self:center;align-items:center;padding:0;transition:all .15s cubic-bezier(.4,0,.2,1);display:flex}.glass-toast__close:hover{background-color:var(--gt-close-bg-hover);border-color:var(--gt-close-border-hover);color:var(--gt-close-text-hover)}.glass-toast__close:focus-visible{outline:2px solid var(--gt-focus-ring);outline-offset:2px}.glass-toast__close svg{width:.875rem;height:.875rem;display:block}.glass-toast__bar{background-color:var(--gt-bar);opacity:.4;border-radius:9999px;height:2px;position:absolute;bottom:0;left:0}@media (width>=768px){.glass-toast__message{font-size:14px}}@media (prefers-color-scheme:dark){:where(:root:not([data-theme=light]):not(.light)) .glass-toast{--gt-bg:#1c1c1eb8;--gt-bg-opaque:#1c1c1eeb;--gt-border:#ffffff1a;--gt-text:#e5e7eb;--gt-close-bg:#ffffff0f;--gt-close-border:#ffffff1f;--gt-close-text:#cbd5e1;--gt-close-bg-hover:#ffffff1f;--gt-close-border-hover:#ffffff38;--gt-close-text-hover:#f1f5f9;--gt-focus-ring:#93c5fd}}:where([data-theme=dark],.dark) .glass-toast{--gt-bg:#1c1c1eb8;--gt-bg-opaque:#1c1c1eeb;--gt-border:#ffffff1a;--gt-text:#e5e7eb;--gt-close-bg:#ffffff0f;--gt-close-border:#ffffff1f;--gt-close-text:#cbd5e1;--gt-close-bg-hover:#ffffff1f;--gt-close-border-hover:#ffffff38;--gt-close-text-hover:#f1f5f9;--gt-focus-ring:#93c5fd}
1
+ .glass-toast-container,.glass-toast,.glass-toast *{box-sizing:border-box}.glass-toast-announcer{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.glass-toast-container{width:min(26rem,100%);max-height:100dvh;padding:1rem;padding-top:max(1rem, env(safe-area-inset-top));padding-right:max(1rem, env(safe-area-inset-right));padding-bottom:max(1rem, env(safe-area-inset-bottom));padding-left:max(1rem, env(safe-area-inset-left));scrollbar-width:none;z-index:2147483647;pointer-events:none;flex-direction:column;gap:.75rem;display:flex;position:fixed;overflow:auto}.glass-toast-container[data-scrollable]{pointer-events:auto}.glass-toast-container--top-right{align-items:flex-end;top:0;right:0}.glass-toast-container--bottom-right{align-items:flex-end;bottom:0;right:0}.glass-toast-container--bottom-center{align-items:center;bottom:0;left:50%;transform:translate(-50%)}.glass-toast{--gt-bg:#fffc;--gt-bg-opaque:#fffffff5;--gt-border:#e5e7eb66;--gt-text:#4a5565;--gt-blur:24px;--gt-radius:1rem;--gt-shadow:0 4px 24px -4px #00000014, 0 1px 2px #0000000a;--gt-close-bg:#f9fafb;--gt-close-border:#e5e7eb;--gt-close-text:#667085;--gt-close-bg-hover:#f3f4f6;--gt-close-border-hover:#d1d5dc;--gt-close-text-hover:#4a5565;--gt-focus-ring:#2563eb;pointer-events:auto;background-color:var(--gt-bg);width:24rem;max-width:calc(100vw - 2rem);backdrop-filter:blur(var(--gt-blur));border:1px solid var(--gt-border);border-radius:var(--gt-radius);box-shadow:var(--gt-shadow);grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:.75rem;padding:.875rem 1rem;display:grid;position:relative;overflow:hidden}.glass-toast-container>.glass-toast{flex:none;max-width:100%}@supports not (backdrop-filter:blur(1px)){.glass-toast{background-color:var(--gt-bg-opaque)}}.glass-toast--success{--gt-pill-bg:#d0fae5;--gt-icon:#047857;--gt-bar:#00bb7f;--gt-ring:16, 185, 129}.glass-toast--error{--gt-pill-bg:#ffe2e2;--gt-icon:#dc2626;--gt-action-text:#b91c1c;--gt-bar:#ff6568;--gt-ring:239, 68, 68}.glass-toast--warning{--gt-pill-bg:#fef3c6;--gt-icon:#b45309;--gt-bar:#fcbb00;--gt-ring:245, 158, 11}.glass-toast--info{--gt-pill-bg:#e2eaf1;--gt-icon:#3a5b7a;--gt-bar:#6f92ad;--gt-ring:76, 112, 144}.glass-toast--animated{transition:all .28s cubic-bezier(0,0,.2,1)}.glass-toast--leaving{transition-timing-function:cubic-bezier(.4,0,1,1)}.glass-toast--enter,.glass-toast--faded{opacity:0}.glass-toast--enter[data-position=top-right],.glass-toast--enter[data-position=bottom-right]{transform:translate(2rem)}.glass-toast--enter[data-position=bottom-center]{transform:translateY(2rem)}.glass-toast__icon{background-color:var(--gt-pill-bg);width:1.75rem;height:1.75rem;color:var(--gt-icon);border-radius:.5rem;flex-shrink:0;justify-content:center;align-items:center;display:flex}.glass-toast__icon svg{flex-shrink:0;width:18px;height:18px;display:block}.glass-toast__message{min-width:0;color:var(--gt-text);overflow-wrap:anywhere;-webkit-line-clamp:5;line-clamp:5;-webkit-box-orient:vertical;margin:0;font-size:.9375rem;line-height:1.625;display:-webkit-box;overflow:hidden}.glass-toast__action{border:1px solid var(--gt-action-border,var(--gt-border));background-color:var(--gt-action-bg,transparent);min-width:0;max-width:100%;min-height:2rem;color:var(--gt-action-text,var(--gt-icon));font:inherit;overflow-wrap:anywhere;cursor:pointer;appearance:none;border-radius:.5rem;grid-area:2/2;place-self:center start;padding:.3125rem .75rem;font-size:.8125rem;font-weight:600;line-height:1.25;transition:background-color .15s cubic-bezier(.4,0,.2,1),border-color .15s cubic-bezier(.4,0,.2,1)}.glass-toast__action:hover{background-color:var(--gt-action-bg-hover,var(--gt-pill-bg))}.glass-toast__action[aria-disabled=true]{cursor:progress}.glass-toast__action:focus-visible{outline:2px solid var(--gt-focus-ring);outline-offset:2px}.glass-toast__close{border:1px solid var(--gt-close-border);background-color:var(--gt-close-bg);width:2rem;height:2rem;color:var(--gt-close-text);font:inherit;cursor:pointer;appearance:none;border-radius:9999px;grid-area:1/-2;justify-content:center;align-self:center;align-items:center;padding:0;transition:all .15s cubic-bezier(.4,0,.2,1);display:flex}.glass-toast__close:hover{background-color:var(--gt-close-bg-hover);border-color:var(--gt-close-border-hover);color:var(--gt-close-text-hover)}.glass-toast__close:focus-visible{outline:2px solid var(--gt-focus-ring);outline-offset:2px}.glass-toast__close svg{width:.875rem;height:.875rem;display:block}.glass-toast__bar{background-color:var(--gt-bar);opacity:.4;border-radius:9999px;height:2px;position:absolute;bottom:0;left:0}@media (width>=768px){.glass-toast__message{font-size:14px}.glass-toast:has(.glass-toast__action){grid-template-columns:auto minmax(0,1fr) minmax(0,35%) auto}.glass-toast:has(.glass-toast__action) .glass-toast__action{grid-area:1/3}}@media (prefers-color-scheme:dark){:where(:root:not([data-theme=light]):not(.light)) .glass-toast{--gt-bg:#1c1c1eb8;--gt-bg-opaque:#1c1c1eeb;--gt-border:#ffffff1a;--gt-text:#e5e7eb;--gt-close-bg:#ffffff0f;--gt-close-border:#ffffff1f;--gt-close-text:#cbd5e1;--gt-close-bg-hover:#ffffff1f;--gt-close-border-hover:#ffffff38;--gt-close-text-hover:#f1f5f9;--gt-focus-ring:#93c5fd;--gt-action-text:var(--gt-text);--gt-action-bg-hover:var(--gt-close-bg-hover)}}:where([data-theme=dark],.dark) .glass-toast{--gt-bg:#1c1c1eb8;--gt-bg-opaque:#1c1c1eeb;--gt-border:#ffffff1a;--gt-text:#e5e7eb;--gt-close-bg:#ffffff0f;--gt-close-border:#ffffff1f;--gt-close-text:#cbd5e1;--gt-close-bg-hover:#ffffff1f;--gt-close-border-hover:#ffffff38;--gt-close-text-hover:#f1f5f9;--gt-focus-ring:#93c5fd;--gt-action-text:var(--gt-text);--gt-action-bg-hover:var(--gt-close-bg-hover)}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,2 +1 @@
1
- import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c } from "./toast-Bh3vjjkJ.js";
2
- export { c as dismissAll, i as ensureStyles, o as error, n as info, e as register, a as resume, s as show, t as success, r as warning };
1
+ export { t as dismissAll, n as ensureStyles, r as error, i as info, a as register, o as resume, s as show, c as success, l as warning } from "./toast-GM0D-R2d.js";