@charcoal-ui/react 6.1.0-beta.0 → 6.1.0-beta.1

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.
Files changed (65) hide show
  1. package/dist/components/Notification/NotificationItem.cjs +30 -0
  2. package/dist/components/Notification/NotificationItem.cjs.map +1 -0
  3. package/dist/components/Notification/NotificationItem.d.ts +15 -0
  4. package/dist/components/Notification/NotificationItem.d.ts.map +1 -0
  5. package/dist/components/Notification/NotificationItem.js +30 -0
  6. package/dist/components/Notification/NotificationItem.js.map +1 -0
  7. package/dist/components/Notification/NotificationRegion.cjs +50 -0
  8. package/dist/components/Notification/NotificationRegion.cjs.map +1 -0
  9. package/dist/components/Notification/NotificationRegion.d.ts +14 -0
  10. package/dist/components/Notification/NotificationRegion.d.ts.map +1 -0
  11. package/dist/components/Notification/NotificationRegion.js +50 -0
  12. package/dist/components/Notification/NotificationRegion.js.map +1 -0
  13. package/dist/components/Notification/Snackbar/index.d.ts +45 -0
  14. package/dist/components/Notification/Snackbar/index.d.ts.map +1 -0
  15. package/dist/components/Notification/Snackbar/index2.cjs +99 -0
  16. package/dist/components/Notification/Snackbar/index2.cjs.map +1 -0
  17. package/dist/components/Notification/Snackbar/index2.js +94 -0
  18. package/dist/components/Notification/Snackbar/index2.js.map +1 -0
  19. package/dist/components/Notification/Toast/index.d.ts +28 -0
  20. package/dist/components/Notification/Toast/index.d.ts.map +1 -0
  21. package/dist/components/Notification/Toast/index2.cjs +86 -0
  22. package/dist/components/Notification/Toast/index2.cjs.map +1 -0
  23. package/dist/components/Notification/Toast/index2.js +81 -0
  24. package/dist/components/Notification/Toast/index2.js.map +1 -0
  25. package/dist/components/Notification/types.d.ts +27 -0
  26. package/dist/components/Notification/types.d.ts.map +1 -0
  27. package/dist/components/Notification/useNotificationQueue.cjs +155 -0
  28. package/dist/components/Notification/useNotificationQueue.cjs.map +1 -0
  29. package/dist/components/Notification/useNotificationQueue.d.ts +16 -0
  30. package/dist/components/Notification/useNotificationQueue.d.ts.map +1 -0
  31. package/dist/components/Notification/useNotificationQueue.js +155 -0
  32. package/dist/components/Notification/useNotificationQueue.js.map +1 -0
  33. package/dist/index.cjs +4 -1
  34. package/dist/index.css +1315 -1250
  35. package/dist/index.d.ts +3 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +3 -2
  38. package/dist/layered.css +1315 -1250
  39. package/dist/layered.css.map +1 -1
  40. package/package.json +5 -5
  41. package/src/__tests__/css-output.test.ts +39 -6
  42. package/src/components/Notification/NotificationItem.tsx +51 -0
  43. package/src/components/Notification/NotificationRegion.tsx +76 -0
  44. package/src/components/{Snackbar → Notification/Snackbar}/__snapshots__/index.css.snap +1 -42
  45. package/src/components/{Snackbar → Notification/Snackbar}/index.css +1 -43
  46. package/src/components/{Snackbar → Notification/Snackbar}/index.story.tsx +52 -23
  47. package/src/components/{Snackbar → Notification/Snackbar}/index.test.tsx +61 -11
  48. package/src/components/Notification/Snackbar/index.tsx +131 -0
  49. package/src/components/Notification/Toast/__snapshots__/index.css.snap +62 -0
  50. package/src/components/Notification/Toast/index.css +61 -0
  51. package/src/components/Notification/Toast/index.story.tsx +174 -0
  52. package/src/components/Notification/Toast/index.test.tsx +263 -0
  53. package/src/components/Notification/Toast/index.tsx +86 -0
  54. package/src/components/Notification/__snapshots__/layout.css.snap +47 -0
  55. package/src/components/Notification/layout.css +46 -0
  56. package/src/components/Notification/types.ts +28 -0
  57. package/src/components/Notification/useNotificationQueue.ts +235 -0
  58. package/src/index.ts +14 -2
  59. package/dist/components/Snackbar/index.d.ts +0 -52
  60. package/dist/components/Snackbar/index.d.ts.map +0 -1
  61. package/dist/components/Snackbar/index2.cjs +0 -268
  62. package/dist/components/Snackbar/index2.cjs.map +0 -1
  63. package/dist/components/Snackbar/index2.js +0 -263
  64. package/dist/components/Snackbar/index2.js.map +0 -1
  65. package/src/components/Snackbar/index.tsx +0 -455
@@ -0,0 +1,235 @@
1
+ import { useCallback, useEffect, useRef } from 'react'
2
+ import { useToastState } from 'react-stately/useToastState'
3
+ import type { NotificationName, NotificationOrder } from './types'
4
+
5
+ const DEFAULT_DURATION_MS = 5000
6
+ const ANIMATION_DURATION_MS = 300
7
+
8
+ type QueueItem<TContent, TCloseReason> = {
9
+ content: TContent
10
+ onClose?: (reason: TCloseReason) => void
11
+ }
12
+
13
+ export function useNotificationQueue<
14
+ TContent,
15
+ TCloseReason extends string = never,
16
+ >(
17
+ name: NotificationName,
18
+ {
19
+ duration: durationOption,
20
+ order = 'queue',
21
+ timeoutReason,
22
+ unmountedReason,
23
+ }: {
24
+ duration?: number
25
+ order?: NotificationOrder
26
+ timeoutReason?: TCloseReason
27
+ unmountedReason?: TCloseReason
28
+ } = {},
29
+ ) {
30
+ const itemRef = useRef<HTMLDivElement>(null)
31
+ const queueRef = useRef<
32
+ Array<QueueItem<TContent, TCloseReason> & { duration: number }>
33
+ >([])
34
+ const isShowingRef = useRef(false)
35
+ const activeRef = useRef<{
36
+ key: string
37
+ onClose?: (reason: TCloseReason) => void
38
+ reason?: TCloseReason
39
+ notified: boolean
40
+ }>()
41
+ const replaceRef = useRef(false)
42
+ const hoverRef = useRef({
43
+ active: false,
44
+ pending: undefined as (() => void) | undefined,
45
+ })
46
+ // wrapUpdate を固定したまま、後から定義する playNext の最新版を呼ぶ
47
+ const playNextRef = useRef<(() => void) | undefined>(undefined)
48
+
49
+ // wrapUpdate の参照が変わると useToastState が ToastQueue を作り直すため useCallback で固定する
50
+ const wrapUpdate = useCallback(
51
+ function wrapUpdate(
52
+ update: () => void,
53
+ action: 'add' | 'remove' | 'clear',
54
+ ) {
55
+ if (action !== 'remove') {
56
+ update()
57
+ return
58
+ }
59
+
60
+ function notifyActive() {
61
+ const active = activeRef.current
62
+ if (active === undefined || active.notified) return
63
+ active.notified = true
64
+ const reason = active.reason ?? timeoutReason
65
+ if (reason !== undefined) {
66
+ active.onClose?.(reason)
67
+ }
68
+ }
69
+
70
+ function finish() {
71
+ activeRef.current = undefined
72
+ update()
73
+ playNextRef.current?.()
74
+ }
75
+
76
+ notifyActive()
77
+
78
+ if (hoverRef.current.active) {
79
+ hoverRef.current.pending = () => wrapUpdate(update, 'remove')
80
+ return
81
+ }
82
+
83
+ if (itemRef.current === null) {
84
+ finish()
85
+ return
86
+ }
87
+
88
+ if (replaceRef.current) {
89
+ replaceRef.current = false
90
+ finish()
91
+ return
92
+ }
93
+ const item: HTMLDivElement = itemRef.current
94
+
95
+ // allow-discreteが Newly Available で使えないので、要素の削除をアニメーション完了まで待つ
96
+ item.dataset.exiting = 'true'
97
+ let completed = false
98
+ let fallbackTimer = 0 // complete 内で clearTimeout(setTimeout(...)) すると新規タイマーを即キャンセルしてしまう
99
+ function handleAnimationEnd(event: AnimationEvent) {
100
+ if (
101
+ event.target === item &&
102
+ event.animationName === `charcoal-${name}-exit`
103
+ ) {
104
+ complete()
105
+ }
106
+ }
107
+ function complete() {
108
+ if (completed) return
109
+ completed = true
110
+ item.removeEventListener('animationend', handleAnimationEnd)
111
+ window.clearTimeout(fallbackTimer)
112
+ finish()
113
+ }
114
+ item.addEventListener('animationend', handleAnimationEnd)
115
+ fallbackTimer = window.setTimeout(complete, ANIMATION_DURATION_MS + 100)
116
+ if (window.matchMedia?.('(prefers-reduced-motion: reduce)').matches) {
117
+ complete()
118
+ }
119
+ },
120
+ [name, timeoutReason],
121
+ )
122
+
123
+ const state = useToastState<TContent>({
124
+ maxVisibleToasts: 1,
125
+ wrapUpdate,
126
+ })
127
+
128
+ useEffect(() => {
129
+ return () => {
130
+ const active = activeRef.current
131
+ if (active !== undefined && !active.notified) {
132
+ if (unmountedReason !== undefined) {
133
+ active.onClose?.(unmountedReason)
134
+ }
135
+ }
136
+ activeRef.current = undefined
137
+ queueRef.current = []
138
+ isShowingRef.current = false
139
+ }
140
+ }, [unmountedReason])
141
+
142
+ function playNext() {
143
+ const next = queueRef.current.shift()
144
+ if (next === undefined) {
145
+ isShowingRef.current = false
146
+ return
147
+ }
148
+
149
+ const { duration, onClose, content } = next
150
+ isShowingRef.current = true
151
+ const enterMs = window.matchMedia?.('(prefers-reduced-motion: reduce)')
152
+ .matches
153
+ ? 0
154
+ : ANIMATION_DURATION_MS
155
+ const key = state.add(content, {
156
+ // react-stately は 0 を「タイマーなし」と扱うため、最小の正数を渡す
157
+ timeout: Math.max(1, duration + enterMs),
158
+ })
159
+ activeRef.current = { key, onClose, notified: false }
160
+ }
161
+ playNextRef.current = playNext
162
+
163
+ function enqueue(
164
+ content: TContent,
165
+ onClose?: (reason: TCloseReason) => void,
166
+ ) {
167
+ const duration =
168
+ typeof durationOption === 'number' && Number.isFinite(durationOption)
169
+ ? Math.max(0, durationOption)
170
+ : DEFAULT_DURATION_MS
171
+
172
+ queueRef.current.push({
173
+ content,
174
+ onClose,
175
+ duration,
176
+ })
177
+ if (!isShowingRef.current) {
178
+ playNext()
179
+ } else if (order === 'replace') {
180
+ const active = activeRef.current
181
+ if (active === undefined) return
182
+
183
+ active.reason = 'replaced' as TCloseReason
184
+ replaceRef.current = true
185
+ hoverRef.current.active = false
186
+ const pending = hoverRef.current.pending
187
+ hoverRef.current.pending = undefined
188
+ if (pending !== undefined) {
189
+ pending()
190
+ } else {
191
+ state.close(active.key)
192
+ }
193
+ }
194
+ }
195
+
196
+ function close(key: string, reason: TCloseReason) {
197
+ const active = activeRef.current
198
+ if (active?.key !== key) return
199
+ active.reason = reason
200
+ hoverRef.current.active = false
201
+ const pending = hoverRef.current.pending
202
+ hoverRef.current.pending = undefined
203
+ if (pending !== undefined) {
204
+ pending()
205
+ } else {
206
+ state.close(key)
207
+ }
208
+ }
209
+
210
+ function onHoverStart() {
211
+ hoverRef.current.active = true
212
+ }
213
+
214
+ function onHoverEnd() {
215
+ hoverRef.current.active = false
216
+ const pending = hoverRef.current.pending
217
+ hoverRef.current.pending = undefined
218
+ pending?.()
219
+ }
220
+
221
+ function clearHover() {
222
+ hoverRef.current.active = false
223
+ hoverRef.current.pending = undefined
224
+ }
225
+
226
+ return {
227
+ state,
228
+ itemRef,
229
+ enqueue,
230
+ close,
231
+ onHoverStart,
232
+ onHoverEnd,
233
+ clearHover,
234
+ }
235
+ }
package/src/index.ts CHANGED
@@ -111,6 +111,18 @@ export {
111
111
  useSnackbar as unstable_useSnackbar,
112
112
  type SnackbarProps as unstable_SnackbarProps,
113
113
  type SnackbarHandler as unstable_SnackbarHandler,
114
- type SnackbarShowOptions as unstable_SnackbarShowOptions,
115
- } from './components/Snackbar'
114
+ type SnackbarCloseReason as unstable_SnackbarCloseReason,
115
+ type ShowSnackbarOptions as unstable_ShowSnackbarOptions,
116
+ } from './components/Notification/Snackbar'
117
+ export {
118
+ default as unstable_Toast,
119
+ useToast as unstable_useToast,
120
+ type ToastProps as unstable_ToastProps,
121
+ type ToastHandler as unstable_ToastHandler,
122
+ type ShowToastOptions as unstable_ShowToastOptions,
123
+ } from './components/Notification/Toast'
124
+ export {
125
+ type NotificationOrder as unstable_NotificationOrder,
126
+ type UseNotificationOptions as unstable_UseNotificationOptions,
127
+ } from './components/Notification/types'
116
128
  import './components/FocusRing/index.css'
@@ -1,52 +0,0 @@
1
- import './index.css';
2
- import type { ElementType, ReactNode } from 'react';
3
- import { type ButtonProps } from '../Button';
4
- type SnackbarPosition = 'top' | 'bottom';
5
- type SnackbarButtonOption<T extends ElementType = 'button'> = Omit<ButtonProps<T>, 'component' | 'className' | 'size'> & {
6
- /**
7
- * ボタンのルート要素として使用するコンポーネント。ページ遷移を伴う場合は `Link` を指定する
8
- * @default 'button'
9
- * @example 'Link'
10
- */
11
- component?: T;
12
- } & ('button' extends T ? unknown : {
13
- component: T;
14
- });
15
- export type SnackbarShowOptions<T extends ElementType = 'button'> = {
16
- /**
17
- * Snackbar を表示する時間(ミリ秒)。負の値は 0、数値でない値は 5000 として扱う
18
- * @default 5000
19
- */
20
- duration?: number;
21
- /**
22
- * Snackbar の右側に表示するボタン
23
- */
24
- button?: SnackbarButtonOption<T>;
25
- };
26
- export type SnackbarHandler = {
27
- show: <T extends ElementType = 'button'>(message: ReactNode, options?: SnackbarShowOptions<T>) => void;
28
- };
29
- export type SnackbarProps = {
30
- /**
31
- * Snackbar の表示位置。ボタン付きの場合は `bottom` に固定される
32
- * @default 'bottom'
33
- */
34
- position?: SnackbarPosition;
35
- /**
36
- * 画面端からの距離(ピクセル)
37
- * @default 16
38
- */
39
- offset?: number;
40
- /**
41
- * 暗い背景色
42
- * @default false
43
- */
44
- dim?: boolean;
45
- zIndex?: number;
46
- portalContainer?: HTMLElement;
47
- className?: string;
48
- };
49
- declare const Snackbar: import("react").ForwardRefExoticComponent<SnackbarProps & import("react").RefAttributes<SnackbarHandler>>;
50
- export default Snackbar;
51
- export declare function useSnackbar(props?: SnackbarProps): readonly [import("react/jsx-runtime").JSX.Element, <T extends ElementType = "button">(message: ReactNode, options?: SnackbarShowOptions<T>) => void];
52
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Snackbar/index.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AASpB,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAa,MAAM,OAAO,CAAA;AAS9D,OAAe,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAOpD,KAAK,gBAAgB,GAAG,KAAK,GAAG,QAAQ,CAAA;AAExC,KAAK,oBAAoB,CAAC,CAAC,SAAS,WAAW,GAAG,QAAQ,IAAI,IAAI,CAChE,WAAW,CAAC,CAAC,CAAC,EACd,WAAW,GAAG,WAAW,GAAG,MAAM,CACnC,GAAG;IACF;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,CAAA;CACd,GAAG,CAAC,QAAQ,SAAS,CAAC,GAAG,OAAO,GAAG;IAAE,SAAS,EAAE,CAAC,CAAA;CAAE,CAAC,CAAA;AAErD,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,WAAW,GAAG,QAAQ,IAAI;IAClE;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,CAAC,CAAC,SAAS,WAAW,GAAG,QAAQ,EACrC,OAAO,EAAE,SAAS,EAClB,OAAO,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAC7B,IAAI,CAAA;CACV,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B;;;OAGG;IACH,QAAQ,CAAC,EAAE,gBAAgB,CAAA;IAC3B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,WAAW,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAeD,QAAA,MAAM,QAAQ,2GA6JZ,CAAA;eAEa,QAAQ;AAEvB,wBAAgB,WAAW,CAAC,KAAK,GAAE,aAAkB,uDAgBrC,CAAC,SAAS,WAAW,sBACxB,SAAS,YACR,mBAAmB,CAAC,CAAC,CAAC,WAKnC"}
@@ -1,268 +0,0 @@
1
- "use client";
2
- const require_useClassNames = require('../../_lib/useClassNames.cjs');
3
- const require_index = require('../Button/index2.cjs');
4
- require('./index.cjs');
5
- let react = require("react");
6
- let react_jsx_runtime = require("react/jsx-runtime");
7
- let react_aria_Overlay = require("react-aria/Overlay");
8
- let react_compiler_runtime = require("react-compiler-runtime");
9
- let react_aria_useToast = require("react-aria/useToast");
10
- let react_stately_useToastState = require("react-stately/useToastState");
11
-
12
- //#region src/components/Snackbar/index.tsx
13
- const DEFAULT_DURATION_MS = 5e3;
14
- const DEFAULT_Z_INDEX = 20;
15
- const ENTER_ANIMATION_DURATION_MS = 300;
16
- const Snackbar = (0, react.forwardRef)(function Snackbar({ position = "bottom", offset = 16, dim = false, zIndex = DEFAULT_Z_INDEX, portalContainer, className }, ref) {
17
- "use memo";
18
- const snackbarRef = (0, react.useRef)(null);
19
- const queueRef = (0, react.useRef)([]);
20
- const isShowingRef = (0, react.useRef)(false);
21
- const hoverRef = (0, react.useRef)({
22
- active: false,
23
- pending: void 0
24
- });
25
- const playNextRef = (0, react.useRef)(void 0);
26
- const state = (0, react_stately_useToastState.useToastState)({
27
- maxVisibleToasts: 1,
28
- wrapUpdate: (0, react.useCallback)(function wrapToastUpdate(update, action) {
29
- if (action !== "remove") {
30
- update();
31
- return;
32
- }
33
- function finish() {
34
- update();
35
- playNextRef.current?.();
36
- }
37
- if (hoverRef.current.active) {
38
- hoverRef.current.pending = () => wrapToastUpdate(update, "remove");
39
- return;
40
- }
41
- if (snackbarRef.current === null) {
42
- finish();
43
- return;
44
- }
45
- const snackbar = snackbarRef.current;
46
- snackbar.dataset.exiting = "true";
47
- let completed = false;
48
- let fallbackTimer = 0;
49
- function handleAnimationEnd(event) {
50
- if (event.target === snackbar && event.animationName === "charcoal-snackbar-exit") complete();
51
- }
52
- function complete() {
53
- if (completed) return;
54
- completed = true;
55
- snackbar.removeEventListener("animationend", handleAnimationEnd);
56
- window.clearTimeout(fallbackTimer);
57
- finish();
58
- }
59
- snackbar.addEventListener("animationend", handleAnimationEnd);
60
- fallbackTimer = window.setTimeout(complete, 400);
61
- if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) complete();
62
- }, [])
63
- });
64
- (0, react.useEffect)(() => {
65
- return () => {
66
- queueRef.current = [];
67
- isShowingRef.current = false;
68
- };
69
- }, []);
70
- function playNext() {
71
- const next = queueRef.current.shift();
72
- if (next === void 0) {
73
- isShowingRef.current = false;
74
- return;
75
- }
76
- const { duration, ...content } = next;
77
- isShowingRef.current = true;
78
- const enterMs = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ? 0 : ENTER_ANIMATION_DURATION_MS;
79
- state.add(content, { timeout: Math.max(1, duration + enterMs) });
80
- }
81
- playNextRef.current = playNext;
82
- function show(message, options = {}) {
83
- const { duration: durationOption = DEFAULT_DURATION_MS, button } = options;
84
- const duration_0 = typeof durationOption === "number" && Number.isFinite(durationOption) ? Math.max(0, durationOption) : DEFAULT_DURATION_MS;
85
- queueRef.current.push({
86
- message,
87
- button,
88
- duration: duration_0
89
- });
90
- if (!isShowingRef.current) playNext();
91
- }
92
- (0, react.useImperativeHandle)(ref, () => ({ show }));
93
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SnackbarRegion, {
94
- state,
95
- position,
96
- offset,
97
- dim,
98
- zIndex,
99
- portalContainer,
100
- className,
101
- snackbarRef,
102
- onHoverStart: () => {
103
- hoverRef.current.active = true;
104
- },
105
- onHoverEnd: () => {
106
- hoverRef.current.active = false;
107
- const pending = hoverRef.current.pending;
108
- hoverRef.current.pending = void 0;
109
- pending?.();
110
- },
111
- onActionClose: () => {
112
- hoverRef.current.active = false;
113
- hoverRef.current.pending = void 0;
114
- }
115
- });
116
- });
117
- function useSnackbar(t0) {
118
- "use memo";
119
- const $ = (0, react_compiler_runtime.c)(13);
120
- if ($[0] !== "48b810b1254edf94a70dbb5631d15f47f0d432d4831df67ae86f2f07a6c66338") {
121
- for (let $i = 0; $i < 13; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
122
- $[0] = "48b810b1254edf94a70dbb5631d15f47f0d432d4831df67ae86f2f07a6c66338";
123
- }
124
- let t1;
125
- if ($[1] !== t0) {
126
- t1 = t0 === void 0 ? {} : t0;
127
- $[1] = t0;
128
- $[2] = t1;
129
- } else t1 = $[2];
130
- const { position, offset, dim, zIndex, portalContainer, className } = t1;
131
- const snackbarHandlerRef = (0, react.useRef)(null);
132
- let t2;
133
- if ($[3] !== className || $[4] !== dim || $[5] !== offset || $[6] !== portalContainer || $[7] !== position || $[8] !== zIndex) {
134
- t2 = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Snackbar, {
135
- ref: snackbarHandlerRef,
136
- position,
137
- offset,
138
- dim,
139
- zIndex,
140
- portalContainer,
141
- className
142
- });
143
- $[3] = className;
144
- $[4] = dim;
145
- $[5] = offset;
146
- $[6] = portalContainer;
147
- $[7] = position;
148
- $[8] = zIndex;
149
- $[9] = t2;
150
- } else t2 = $[9];
151
- const element = t2;
152
- let t3;
153
- if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
154
- t3 = function show(message, options) {
155
- snackbarHandlerRef.current?.show(message, options);
156
- };
157
- $[10] = t3;
158
- } else t3 = $[10];
159
- const show = t3;
160
- let t4;
161
- if ($[11] !== element) {
162
- t4 = [element, show];
163
- $[11] = element;
164
- $[12] = t4;
165
- } else t4 = $[12];
166
- return t4;
167
- }
168
- function SnackbarRegion({ state, position, offset, dim, zIndex, portalContainer, className, snackbarRef, onHoverStart, onHoverEnd, onActionClose }) {
169
- const regionRef = (0, react.useRef)(null);
170
- const pausedByFocusRef = (0, react.useRef)(false);
171
- const { regionProps } = (0, react_aria_useToast.useToastRegion)({}, {
172
- ...state,
173
- pauseAll() {
174
- if (regionRef.current?.contains(document.activeElement)) {
175
- pausedByFocusRef.current = true;
176
- state.pauseAll();
177
- }
178
- },
179
- resumeAll() {
180
- if (pausedByFocusRef.current) {
181
- pausedByFocusRef.current = false;
182
- state.resumeAll();
183
- }
184
- }
185
- }, regionRef);
186
- const classNames = require_useClassNames.useClassNames("charcoal-snackbar-region", className);
187
- if (state.visibleToasts.length === 0) return null;
188
- const effectivePosition = state.visibleToasts.some((toast) => toast.content.button !== void 0) ? "bottom" : position;
189
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_aria_Overlay.Overlay, {
190
- disableFocusManagement: true,
191
- portalContainer,
192
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
193
- ...regionProps,
194
- ref: regionRef,
195
- className: classNames,
196
- "data-position": effectivePosition,
197
- style: {
198
- zIndex,
199
- "--charcoal-snackbar-offset": `${offset}px`
200
- },
201
- children: state.visibleToasts.map((toast) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SnackbarItem, {
202
- toast,
203
- state,
204
- dim,
205
- snackbarRef,
206
- onHoverStart,
207
- onHoverEnd,
208
- onActionClose: () => {
209
- onActionClose();
210
- state.close(toast.key);
211
- }
212
- }, toast.key))
213
- })
214
- });
215
- }
216
- function SnackbarItem({ toast, state, dim, snackbarRef, onHoverStart, onHoverEnd, onActionClose }) {
217
- const { toastProps, contentProps, titleProps } = (0, react_aria_useToast.useToast)({ toast }, state, snackbarRef);
218
- const { message, button } = toast.content;
219
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
220
- ...toastProps,
221
- ref: snackbarRef,
222
- className: "charcoal-snackbar",
223
- "data-dim": dim,
224
- "data-with-button": button !== void 0,
225
- onPointerEnter: onHoverStart,
226
- onPointerLeave: onHoverEnd,
227
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
228
- ...contentProps,
229
- role: "status",
230
- className: "charcoal-snackbar-content",
231
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
232
- ...titleProps,
233
- className: "charcoal-snackbar-label",
234
- children: message
235
- })
236
- }), button !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SnackbarAction, {
237
- button,
238
- dim,
239
- onClose: onActionClose
240
- })]
241
- });
242
- }
243
- function SnackbarAction({ button, dim, onClose }) {
244
- const { onClick, variant, children: buttonChildren, ...buttonProps } = button;
245
- function handleButtonClick(event) {
246
- onClick?.(event);
247
- onClose();
248
- }
249
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PolymorphicButton, {
250
- ...buttonProps,
251
- size: "S",
252
- variant: variant ?? (dim ? "Navigation" : void 0),
253
- onClick: handleButtonClick,
254
- children: buttonChildren
255
- });
256
- }
257
- function PolymorphicButton({ component, ...props }) {
258
- if (component === void 0 || component === "button") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_index.default, { ...props });
259
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_index.default, {
260
- ...props,
261
- component
262
- });
263
- }
264
-
265
- //#endregion
266
- exports.default = Snackbar;
267
- exports.useSnackbar = useSnackbar;
268
- //# sourceMappingURL=index2.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index2.cjs","names":["wrapToastUpdate","duration","snackbarHandlerRef","position","offset","dim","zIndex","portalContainer","className"],"sources":["../../../src/components/Snackbar/index.tsx"],"sourcesContent":["import './index.css'\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n} from 'react'\nimport type { ElementType, ReactNode, RefObject } from 'react'\nimport { Overlay } from 'react-aria/Overlay'\nimport { useToast, useToastRegion } from 'react-aria/useToast'\nimport {\n useToastState,\n type QueuedToast,\n type ToastState,\n} from 'react-stately/useToastState'\nimport { useClassNames } from '../../_lib/useClassNames'\nimport Button, { type ButtonProps } from '../Button'\n\nconst DEFAULT_DURATION_MS = 5000\nconst DEFAULT_Z_INDEX = 20\nconst ENTER_ANIMATION_DURATION_MS = 300\nconst EXIT_ANIMATION_DURATION_MS = 300\n\ntype SnackbarPosition = 'top' | 'bottom'\n\ntype SnackbarButtonOption<T extends ElementType = 'button'> = Omit<\n ButtonProps<T>,\n 'component' | 'className' | 'size'\n> & {\n /**\n * ボタンのルート要素として使用するコンポーネント。ページ遷移を伴う場合は `Link` を指定する\n * @default 'button'\n * @example 'Link'\n */\n component?: T\n} & ('button' extends T ? unknown : { component: T })\n\nexport type SnackbarShowOptions<T extends ElementType = 'button'> = {\n /**\n * Snackbar を表示する時間(ミリ秒)。負の値は 0、数値でない値は 5000 として扱う\n * @default 5000\n */\n duration?: number\n /**\n * Snackbar の右側に表示するボタン\n */\n button?: SnackbarButtonOption<T>\n}\n\nexport type SnackbarHandler = {\n show: <T extends ElementType = 'button'>(\n message: ReactNode,\n options?: SnackbarShowOptions<T>,\n ) => void\n}\n\nexport type SnackbarProps = {\n /**\n * Snackbar の表示位置。ボタン付きの場合は `bottom` に固定される\n * @default 'bottom'\n */\n position?: SnackbarPosition\n /**\n * 画面端からの距離(ピクセル)\n * @default 16\n */\n offset?: number\n /**\n * 暗い背景色\n * @default false\n */\n dim?: boolean\n zIndex?: number\n portalContainer?: HTMLElement\n className?: string\n}\n\ntype SnackbarContent = {\n message: ReactNode\n button?: SnackbarButtonContent\n}\n\ntype QueuedSnackbar = SnackbarContent & {\n duration: number\n}\n\ntype SnackbarButtonContent = Omit<SnackbarButtonOption, 'component'> & {\n component?: ElementType\n}\n\nconst Snackbar = forwardRef<SnackbarHandler, SnackbarProps>(function Snackbar(\n {\n position = 'bottom',\n offset = 16,\n dim = false,\n zIndex = DEFAULT_Z_INDEX,\n portalContainer,\n className,\n },\n ref,\n) {\n 'use memo'\n\n const snackbarRef = useRef<HTMLDivElement>(null)\n const queueRef = useRef<QueuedSnackbar[]>([])\n const isShowingRef = useRef(false)\n const hoverRef = useRef({\n active: false,\n pending: undefined as (() => void) | undefined,\n })\n // wrapUpdate を固定したまま、後から定義する playNext の最新版を呼ぶ\n const playNextRef = useRef<(() => void) | undefined>(undefined)\n\n // wrapUpdate の参照が変わると useToastState が ToastQueue を作り直すため useCallback で固定する\n const wrapToastUpdate = useCallback(function wrapToastUpdate(\n update: () => void,\n action: 'add' | 'remove' | 'clear',\n ) {\n if (action !== 'remove') {\n update()\n return\n }\n\n function finish() {\n update()\n playNextRef.current?.()\n }\n\n if (hoverRef.current.active) {\n hoverRef.current.pending = () => wrapToastUpdate(update, 'remove')\n return\n }\n\n if (snackbarRef.current === null) {\n finish()\n return\n }\n const snackbar: HTMLDivElement = snackbarRef.current\n\n // allow-discreteが Newly Available で使えないので、要素の削除をアニメーション完了まで待つ\n snackbar.dataset.exiting = 'true'\n let completed = false\n let fallbackTimer = 0 // complete 内で clearTimeout(setTimeout(...)) すると新規タイマーを即キャンセルしてしまう\n function handleAnimationEnd(event: AnimationEvent) {\n if (\n event.target === snackbar &&\n event.animationName === 'charcoal-snackbar-exit'\n ) {\n complete()\n }\n }\n function complete() {\n if (completed) return\n completed = true\n snackbar.removeEventListener('animationend', handleAnimationEnd)\n window.clearTimeout(fallbackTimer)\n finish()\n }\n snackbar.addEventListener('animationend', handleAnimationEnd)\n fallbackTimer = window.setTimeout(\n complete,\n EXIT_ANIMATION_DURATION_MS + 100,\n )\n if (window.matchMedia?.('(prefers-reduced-motion: reduce)').matches) {\n complete()\n }\n }, [])\n\n const state = useToastState<SnackbarContent>({\n maxVisibleToasts: 1,\n wrapUpdate: wrapToastUpdate,\n })\n\n useEffect(() => {\n return () => {\n queueRef.current = []\n isShowingRef.current = false\n }\n }, [])\n\n function playNext() {\n const next = queueRef.current.shift()\n if (next === undefined) {\n isShowingRef.current = false\n return\n }\n\n const { duration, ...content } = next\n isShowingRef.current = true\n const enterMs = window.matchMedia?.('(prefers-reduced-motion: reduce)')\n .matches\n ? 0\n : ENTER_ANIMATION_DURATION_MS\n state.add(content, {\n // react-stately は 0 を「タイマーなし」と扱うため、最小の正数を渡す\n timeout: Math.max(1, duration + enterMs),\n })\n }\n playNextRef.current = playNext\n\n function show<T extends ElementType = 'button'>(\n message: ReactNode,\n options: SnackbarShowOptions<T> = {},\n ) {\n const { duration: durationOption = DEFAULT_DURATION_MS, button } = options\n const duration =\n typeof durationOption === 'number' && Number.isFinite(durationOption)\n ? Math.max(0, durationOption)\n : DEFAULT_DURATION_MS\n\n queueRef.current.push({\n message,\n button: button as SnackbarButtonContent | undefined,\n duration,\n })\n if (!isShowingRef.current) {\n playNext()\n }\n }\n\n useImperativeHandle(ref, () => ({ show }))\n\n return (\n <SnackbarRegion\n state={state}\n position={position}\n offset={offset}\n dim={dim}\n zIndex={zIndex}\n portalContainer={portalContainer}\n className={className}\n snackbarRef={snackbarRef}\n onHoverStart={() => {\n hoverRef.current.active = true\n }}\n onHoverEnd={() => {\n hoverRef.current.active = false\n const pending = hoverRef.current.pending\n hoverRef.current.pending = undefined\n pending?.()\n }}\n onActionClose={() => {\n hoverRef.current.active = false\n hoverRef.current.pending = undefined\n }}\n />\n )\n})\n\nexport default Snackbar\n\nexport function useSnackbar(props: SnackbarProps = {}) {\n 'use memo'\n\n const { position, offset, dim, zIndex, portalContainer, className } = props\n const snackbarHandlerRef = useRef<SnackbarHandler>(null)\n const element = (\n <Snackbar\n ref={snackbarHandlerRef}\n position={position}\n offset={offset}\n dim={dim}\n zIndex={zIndex}\n portalContainer={portalContainer}\n className={className}\n />\n )\n function show<T extends ElementType = 'button'>(\n message: ReactNode,\n options?: SnackbarShowOptions<T>,\n ) {\n snackbarHandlerRef.current?.show(message, options)\n }\n return [element, show] as const\n}\n\nfunction SnackbarRegion({\n state,\n position,\n offset,\n dim,\n zIndex,\n portalContainer,\n className,\n snackbarRef,\n onHoverStart,\n onHoverEnd,\n onActionClose,\n}: {\n state: ToastState<SnackbarContent>\n position: SnackbarPosition\n offset: number\n dim: boolean\n zIndex: number\n portalContainer?: HTMLElement\n className?: string\n snackbarRef: RefObject<HTMLDivElement>\n onHoverStart: () => void\n onHoverEnd: () => void\n onActionClose: () => void\n}) {\n const regionRef = useRef<HTMLDivElement>(null)\n const pausedByFocusRef = useRef(false)\n const timerState: ToastState<SnackbarContent> = {\n ...state,\n pauseAll() {\n if (regionRef.current?.contains(document.activeElement)) {\n pausedByFocusRef.current = true\n state.pauseAll()\n }\n },\n resumeAll() {\n if (pausedByFocusRef.current) {\n pausedByFocusRef.current = false\n state.resumeAll()\n }\n },\n }\n const { regionProps } = useToastRegion({}, timerState, regionRef)\n const classNames = useClassNames('charcoal-snackbar-region', className)\n\n if (state.visibleToasts.length === 0) {\n return null\n }\n\n // ボタン付きの Snackbar は常に下部に表示される\n const hasButton = state.visibleToasts.some(\n (toast) => toast.content.button !== undefined,\n )\n const effectivePosition = hasButton ? 'bottom' : position\n\n return (\n <Overlay disableFocusManagement portalContainer={portalContainer}>\n <div\n {...regionProps}\n ref={regionRef}\n className={classNames}\n data-position={effectivePosition}\n style={{\n zIndex,\n '--charcoal-snackbar-offset': `${offset}px`,\n }}\n >\n {state.visibleToasts.map((toast) => (\n <SnackbarItem\n key={toast.key}\n toast={toast}\n state={state}\n dim={dim}\n snackbarRef={snackbarRef}\n onHoverStart={onHoverStart}\n onHoverEnd={onHoverEnd}\n onActionClose={() => {\n onActionClose()\n state.close(toast.key)\n }}\n />\n ))}\n </div>\n </Overlay>\n )\n}\n\nfunction SnackbarItem({\n toast,\n state,\n dim,\n snackbarRef,\n onHoverStart,\n onHoverEnd,\n onActionClose,\n}: {\n toast: QueuedToast<SnackbarContent>\n state: ToastState<SnackbarContent>\n dim: boolean\n snackbarRef: RefObject<HTMLDivElement>\n onHoverStart: () => void\n onHoverEnd: () => void\n onActionClose: () => void\n}) {\n const { toastProps, contentProps, titleProps } = useToast(\n { toast },\n state,\n snackbarRef,\n )\n const { message, button } = toast.content\n\n return (\n <div\n {...toastProps}\n ref={snackbarRef}\n className=\"charcoal-snackbar\"\n data-dim={dim}\n data-with-button={button !== undefined}\n onPointerEnter={onHoverStart}\n onPointerLeave={onHoverEnd}\n >\n <div\n {...contentProps}\n role=\"status\"\n className=\"charcoal-snackbar-content\"\n >\n <div {...titleProps} className=\"charcoal-snackbar-label\">\n {message}\n </div>\n </div>\n {button !== undefined && (\n <SnackbarAction button={button} dim={dim} onClose={onActionClose} />\n )}\n </div>\n )\n}\n\nfunction SnackbarAction({\n button,\n dim,\n onClose,\n}: {\n button: SnackbarButtonContent\n dim: boolean\n onClose: () => void\n}) {\n const { onClick, variant, children: buttonChildren, ...buttonProps } = button\n\n function handleButtonClick(\n event: Parameters<NonNullable<ButtonProps<'button'>['onClick']>>[0],\n ) {\n onClick?.(event)\n onClose()\n }\n\n return (\n <PolymorphicButton\n {...buttonProps}\n size=\"S\"\n variant={variant ?? (dim ? 'Navigation' : undefined)}\n onClick={handleButtonClick}\n >\n {buttonChildren}\n </PolymorphicButton>\n )\n}\n\nfunction PolymorphicButton({\n component,\n ...props\n}: Omit<ButtonProps, 'component'> & { component?: ElementType }) {\n if (component === undefined || component === 'button') {\n return <Button {...props} />\n }\n\n return <Button {...props} component={component} />\n}\n"],"mappings":";;;;;;;;;;;;AAoBA,MAAM,sBAAsB;AAC5B,MAAM,kBAAkB;AACxB,MAAM,8BAA8B;AAsEpC,MAAM,iCAAsD,SAAS,SACnE,EACE,WAAW,UACX,SAAS,IACT,MAAM,OACN,SAAS,iBACT,iBACA,aAEF,KACA;CACA;CAEA,MAAM,gCAAqC,IAAI;CAC/C,MAAM,6BAAoC,CAAA,CAAE;CAC5C,MAAM,iCAAsB,KAAK;CACjC,MAAM,6BAAkB;EACtB,QAAQ;EACR,SAAS;CACX,CAAC;CAED,MAAM,gCAA+C,MAAS;CAyD9D,MAAM,uDAAuC;EAC3C,kBAAkB;EAClB,mCAxDkC,SAAS,gBAC3C,QACA,QACA;GACA,IAAI,WAAW,UAAU;IACvB,OAAO;IACP;GACF;GAEA,SAAS,SAAS;IAChB,OAAO;IACP,YAAY,UAAU;GACxB;GAEA,IAAI,SAAS,QAAQ,QAAQ;IAC3B,SAAS,QAAQ,gBAAgB,gBAAgB,QAAQ,QAAQ;IACjE;GACF;GAEA,IAAI,YAAY,YAAY,MAAM;IAChC,OAAO;IACP;GACF;GACA,MAAM,WAA2B,YAAY;GAG7C,SAAS,QAAQ,UAAU;GAC3B,IAAI,YAAY;GAChB,IAAI,gBAAgB;GACpB,SAAS,mBAAmB,OAAuB;IACjD,IACE,MAAM,WAAW,YACjB,MAAM,kBAAkB,0BAExB,SAAS;GAEb;GACA,SAAS,WAAW;IAClB,IAAI,WAAW;IACf,YAAY;IACZ,SAAS,oBAAoB,gBAAgB,kBAAkB;IAC/D,OAAO,aAAa,aAAa;IACjC,OAAO;GACT;GACA,SAAS,iBAAiB,gBAAgB,kBAAkB;GAC5D,gBAAgB,OAAO,WACrB,UACA,GACF;GACA,IAAI,OAAO,aAAa,kCAAkC,CAAC,CAAC,SAC1D,SAAS;EAEb,GAAG,CAAA,CAIWA;CACd,CAAC;CAED,2BAAgB;EACd,aAAa;GACX,SAAS,UAAU,CAAA;GACnB,aAAa,UAAU;EACzB;CACF,GAAG,CAAA,CAAE;CAEL,SAAS,WAAW;EAClB,MAAM,OAAO,SAAS,QAAQ,MAAM;EACpC,IAAI,SAAS,QAAW;GACtB,aAAa,UAAU;GACvB;EACF;EAEA,MAAM,EAAE,UAAU,GAAG,YAAY;EACjC,aAAa,UAAU;EACvB,MAAM,UAAU,OAAO,aAAa,kCAAkC,CAAC,CACpE,UACC,IACA;EACJ,MAAM,IAAI,SAAS,EAEjB,SAAS,KAAK,IAAI,GAAG,WAAW,OAAO,EACzC,CAAC;CACH;CACA,YAAY,UAAU;CAEtB,SAAS,KACP,SACA,UAAkC,CAAC,GACnC;EACA,MAAM,EAAE,UAAU,iBAAiB,qBAAqB,WAAW;EACnE,MAAMC,aACJ,OAAO,mBAAmB,YAAY,OAAO,SAAS,cAAc,IAChE,KAAK,IAAI,GAAG,cAAc,IAC1B;EAEN,SAAS,QAAQ,KAAK;GACpB;GACQ;GACR,UAAAA;EACF,CAAC;EACD,IAAI,CAAC,aAAa,SAChB,SAAS;CAEb;CAEA,+BAAoB,YAAY,EAAE,KAAK,EAAE;CAEzC,OACE,2CAAC,gBAAD;EACS;EACG;EACF;EACH;EACG;EACS;EACN;EACE;EACb,oBAAoB;GAClB,SAAS,QAAQ,SAAS;EAC5B;EACA,kBAAkB;GAChB,SAAS,QAAQ,SAAS;GAC1B,MAAM,UAAU,SAAS,QAAQ;GACjC,SAAS,QAAQ,UAAU;GAC3B,UAAU;EACZ;EACA,qBAAqB;GACnB,SAAS,QAAQ,SAAS;GAC1B,SAAS,QAAQ,UAAU;EAC7B;CAAE;AAGR,CAAC;AAID,SAAO,YAAA,IAAA;CAAA;CAAA,MAAA,kCAAA,EAAA;CAAA,IAAA,EAAA,OAAA,oEAAA;EAAA,KAAA,IAAA,KAAA,GAAA,KAAA,IAAA,MAAA,GAAA,EAAA,MAAA,OAAA,IAAA,2BAAA;EAAA,EAAA,KAAA;CAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,IAAA;EAAqB,KAAA,OAAA,SAAA,CAAwB,IAAxB;EAAyB,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAGnD,MAAA,EAAA,UAAA,QAAA,KAAA,QAAA,iBAAA,cAAsE;CACtE,MAAA,uCAAmD,IAAI;CAAC,IAAA;CAAA,IAAA,EAAA,OAAA,aAAA,EAAA,OAAA,OAAA,EAAA,OAAA,UAAA,EAAA,OAAA,mBAAA,EAAA,OAAA,YAAA,EAAA,OAAA,QAAA;EAEtD,KAAA,2CAAC,UAAD;GACOC,KAAA;GACK;GACF;GACH;GACG;GACS;GACN;EAAS;EACpB,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CATJ,MAAA,UACE;CASD,IAAA;CAAA,IAAA,EAAA,QAAA,OAAA,IAAA,2BAAA,GAAA;EACD,KAAA,SAAA,KAAA,SAAA,SAAA;GAIE,mBAAkB,SAAc,KAAC,SAAS,OAAO;EAAC;EACnD,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CALD,MAAA,OAAA;CAKC,IAAA;CAAA,IAAA,EAAA,QAAA,SAAA;EACM,KAAA,CAAC,SAAS,IAAI;EAAC,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OAAf;AAAwB;AAGjC,SAAS,eAAe,EACtB,OACA,UACA,QACA,KACA,QACA,iBACA,WACA,aACA,cACA,YACA,iBAaC;CACD,MAAM,8BAAmC,IAAI;CAC7C,MAAM,qCAA0B,KAAK;CAgBrC,MAAM,EAAE,wDAA+B,CAAC,GAAG;EAdzC,GAAG;EACH,WAAW;GACT,IAAI,UAAU,SAAS,SAAS,SAAS,aAAa,GAAG;IACvD,iBAAiB,UAAU;IAC3B,MAAM,SAAS;GACjB;EACF;EACA,YAAY;GACV,IAAI,iBAAiB,SAAS;IAC5B,iBAAiB,UAAU;IAC3B,MAAM,UAAU;GAClB;EACF;CAEyC,GAAY,SAAS;CAChE,MAAM,aAAa,oCAAc,4BAA4B,SAAS;CAEtE,IAAI,MAAM,cAAc,WAAW,GACjC,OAAO;CAOT,MAAM,oBAHY,MAAM,cAAc,MACnC,UAAU,MAAM,QAAQ,WAAW,MAEZ,IAAY,WAAW;CAEjD,OACE,2CAAC,4BAAD;EAAS;EAAwC;YAC/C,2CAAC,OAAD;GACE,GAAI;GACJ,KAAK;GACL,WAAW;GACX,iBAAe;GACf,OAAO;IACL;IACA,8BAA8B,GAAG,OAAM;GACzC;aAEC,MAAM,cAAc,KAAK,UACxB,2CAAC,cAAD;IAES;IACA;IACF;IACQ;IACC;IACF;IACZ,qBAAqB;KACnB,cAAc;KACd,MAAM,MAAM,MAAM,GAAG;IACvB;GAAE,GAVG,MAAM,GAUT,CAEL;EACE;CACE;AAEb;AAEA,SAAS,aAAa,EACpB,OACA,OACA,KACA,aACA,cACA,YACA,iBASC;CACD,MAAM,EAAE,YAAY,cAAc,iDAChC,EAAE,MAAM,GACR,OACA,WACF;CACA,MAAM,EAAE,SAAS,WAAW,MAAM;CAElC,OACE,4CAAC,OAAD;EACE,GAAI;EACJ,KAAK;EACL,WAAU;EACV,YAAU;EACV,oBAAkB,WAAW;EAC7B,gBAAgB;EAChB,gBAAgB;YAPlB,CASE,2CAAC,OAAD;GACE,GAAI;GACJ,MAAK;GACL,WAAU;aAEV,2CAAC,OAAD;IAAK,GAAI;IAAY,WAAU;cAC5B;GACE;EACF,IACJ,WAAW,UACV,2CAAC,gBAAD;GAAwB;GAAa;GAAK,SAAS;EAAc,EAEhE;;AAET;AAEA,SAAS,eAAe,EACtB,QACA,KACA,WAKC;CACD,MAAM,EAAE,SAAS,SAAS,UAAU,gBAAgB,GAAG,gBAAgB;CAEvE,SAAS,kBACP,OACA;EACA,UAAU,KAAK;EACf,QAAQ;CACV;CAEA,OACE,2CAAC,mBAAD;EACE,GAAI;EACJ,MAAK;EACL,SAAS,YAAY,MAAM,eAAe;EAC1C,SAAS;YAER;CACgB;AAEvB;AAEA,SAAS,kBAAkB,EACzB,WACA,GAAG,SAC4D;CAC/D,IAAI,cAAc,UAAa,cAAc,UAC3C,OAAO,2CAAC,uBAAD,EAAQ,GAAI,MAAM;CAG3B,OAAO,2CAAC,uBAAD;EAAQ,GAAI;EAAkB;CAAU;AACjD"}