sileo 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -6
- package/dist/index.mjs +51 -6
- package/dist/styles.css +1 -0
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -42,6 +42,7 @@ interface SileoPromiseOptions<T = unknown> {
|
|
|
42
42
|
success: SileoOptions | ((data: T) => SileoOptions);
|
|
43
43
|
error: SileoOptions | ((err: unknown) => SileoOptions);
|
|
44
44
|
action?: SileoOptions | ((data: T) => SileoOptions);
|
|
45
|
+
position?: SileoPosition;
|
|
45
46
|
}
|
|
46
47
|
declare const sileo: {
|
|
47
48
|
show: (opts: SileoOptions) => string;
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sources":["../src/types.ts","../src/toast.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nexport type SileoState =\n\t| \"success\"\n\t| \"loading\"\n\t| \"error\"\n\t| \"warning\"\n\t| \"info\"\n\t| \"action\";\n\nexport interface SileoStyles {\n\ttitle?: string;\n\tdescription?: string;\n\tbadge?: string;\n\tbutton?: string;\n}\n\nexport interface SileoButton {\n\ttitle: string;\n\tonClick: () => void;\n}\n\nexport const SILEO_POSITIONS = [\n\t\"top-left\",\n\t\"top-center\",\n\t\"top-right\",\n\t\"bottom-left\",\n\t\"bottom-center\",\n\t\"bottom-right\",\n] as const;\n\nexport type SileoPosition = (typeof SILEO_POSITIONS)[number];\n\nexport interface SileoOptions {\n\ttitle?: string;\n\tdescription?: ReactNode | string;\n\tposition?: SileoPosition;\n\tduration?: number | null;\n\ticon?: ReactNode | null;\n\tstyles?: SileoStyles;\n\tfill?: string;\n\troundness?: number;\n\tautopilot?: boolean | { expand?: number; collapse?: number };\n\tbutton?: SileoButton;\n}\n","import {\n\ttype CSSProperties,\n\ttype MouseEventHandler,\n\ttype ReactNode,\n\tuseCallback,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { Sileo } from \"./sileo\";\nimport {\n\tSILEO_POSITIONS,\n\ttype SileoOptions,\n\ttype SileoPosition,\n\ttype SileoState,\n} from \"./types\";\n\n/* -------------------------------- Constants ------------------------------- */\n\nconst DEFAULT_DURATION = 6000;\nconst EXIT_DURATION = DEFAULT_DURATION * 0.1;\nconst AUTO_EXPAND_DELAY = DEFAULT_DURATION * 0.025;\nconst AUTO_COLLAPSE_DELAY = DEFAULT_DURATION - 2000;\n\nconst pillAlign = (pos: SileoPosition) =>\n\tpos.includes(\"right\") ? \"right\" : pos.includes(\"center\") ? \"center\" : \"left\";\nconst expandDir = (pos: SileoPosition) =>\n\tpos.startsWith(\"top\") ? (\"bottom\" as const) : (\"top\" as const);\n\n/* ---------------------------------- Types --------------------------------- */\n\ninterface InternalSileoOptions extends SileoOptions {\n\tid?: string;\n\tstate?: SileoState;\n}\n\ninterface SileoItem extends InternalSileoOptions {\n\tid: string;\n\tinstanceId: string;\n\texiting?: boolean;\n\tautoExpandDelayMs?: number;\n\tautoCollapseDelayMs?: number;\n}\n\ntype SileoOffsetValue = number | string;\ntype SileoOffsetConfig = Partial<\n\tRecord<\"top\" | \"right\" | \"bottom\" | \"left\", SileoOffsetValue>\n>;\n\nexport interface SileoToasterProps {\n\tchildren?: ReactNode;\n\tposition?: SileoPosition;\n\toffset?: SileoOffsetValue | SileoOffsetConfig;\n\toptions?: Partial<SileoOptions>;\n}\n\n/* ------------------------------ Global State ------------------------------ */\n\ntype SileoListener = (toasts: SileoItem[]) => void;\n\nconst store = {\n\ttoasts: [] as SileoItem[],\n\tlisteners: new Set<SileoListener>(),\n\tposition: \"top-right\" as SileoPosition,\n\toptions: undefined as Partial<SileoOptions> | undefined,\n\n\temit() {\n\t\tfor (const fn of this.listeners) fn(this.toasts);\n\t},\n\n\tupdate(fn: (prev: SileoItem[]) => SileoItem[]) {\n\t\tthis.toasts = fn(this.toasts);\n\t\tthis.emit();\n\t},\n};\n\nlet idCounter = 0;\nconst generateId = () =>\n\t`${++idCounter}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n\nconst timeoutKey = (t: SileoItem) => `${t.id}:${t.instanceId}`;\n\n/* ------------------------------- Toast API -------------------------------- */\n\nconst dismissToast = (id: string) => {\n\tconst item = store.toasts.find((t) => t.id === id);\n\tif (!item || item.exiting) return;\n\n\tstore.update((prev) =>\n\t\tprev.map((t) => (t.id === id ? { ...t, exiting: true } : t)),\n\t);\n\n\tsetTimeout(\n\t\t() => store.update((prev) => prev.filter((t) => t.id !== id)),\n\t\tEXIT_DURATION,\n\t);\n};\n\nconst resolveAutopilot = (\n\topts: InternalSileoOptions,\n\tduration: number | null,\n): { expandDelayMs?: number; collapseDelayMs?: number } => {\n\tif (opts.autopilot === false || !duration || duration <= 0) return {};\n\tconst cfg = typeof opts.autopilot === \"object\" ? opts.autopilot : undefined;\n\tconst clamp = (v: number) => Math.min(duration, Math.max(0, v));\n\treturn {\n\t\texpandDelayMs: clamp(cfg?.expand ?? AUTO_EXPAND_DELAY),\n\t\tcollapseDelayMs: clamp(cfg?.collapse ?? AUTO_COLLAPSE_DELAY),\n\t};\n};\n\nconst mergeOptions = (options: InternalSileoOptions) => ({\n\t...store.options,\n\t...options,\n\tstyles: { ...store.options?.styles, ...options.styles },\n});\n\nconst buildSileoItem = (\n\tmerged: InternalSileoOptions,\n\tid: string,\n\tfallbackPosition?: SileoPosition,\n): SileoItem => {\n\tconst duration = merged.duration ?? DEFAULT_DURATION;\n\tconst auto = resolveAutopilot(merged, duration);\n\treturn {\n\t\t...merged,\n\t\tid,\n\t\tinstanceId: generateId(),\n\t\tposition: merged.position ?? fallbackPosition ?? store.position,\n\t\tautoExpandDelayMs: auto.expandDelayMs,\n\t\tautoCollapseDelayMs: auto.collapseDelayMs,\n\t};\n};\n\nconst createToast = (options: InternalSileoOptions) => {\n\tconst live = store.toasts.filter((t) => !t.exiting);\n\tconst merged = mergeOptions(options);\n\n\tconst id = merged.id ?? \"sileo-default\";\n\tconst prev = live.find((t) => t.id === id);\n\tconst item = buildSileoItem(merged, id, prev?.position);\n\n\tif (prev) {\n\t\tstore.update((p) => p.map((t) => (t.id === id ? item : t)));\n\t} else {\n\t\tstore.update((p) => [...p, item]);\n\t}\n\treturn { id, duration: merged.duration ?? DEFAULT_DURATION };\n};\n\nconst updateToast = (id: string, options: InternalSileoOptions) => {\n\tconst existing = store.toasts.find((t) => t.id === id);\n\tif (!existing) return;\n\n\tconst item = buildSileoItem(mergeOptions(options), id, existing.position);\n\tstore.update((prev) => prev.map((t) => (t.id === id ? item : t)));\n};\n\nexport interface SileoPromiseOptions<T = unknown> {\n\tloading: Pick<SileoOptions, \"title\" | \"icon\">;\n\tsuccess: SileoOptions | ((data: T) => SileoOptions);\n\terror: SileoOptions | ((err: unknown) => SileoOptions);\n\taction?: SileoOptions | ((data: T) => SileoOptions);\n}\n\nexport const sileo = {\n\tshow: (opts: SileoOptions) => createToast(opts).id,\n\tsuccess: (opts: SileoOptions) =>\n\t\tcreateToast({ ...opts, state: \"success\" }).id,\n\terror: (opts: SileoOptions) => createToast({ ...opts, state: \"error\" }).id,\n\twarning: (opts: SileoOptions) =>\n\t\tcreateToast({ ...opts, state: \"warning\" }).id,\n\tinfo: (opts: SileoOptions) => createToast({ ...opts, state: \"info\" }).id,\n\taction: (opts: SileoOptions) => createToast({ ...opts, state: \"action\" }).id,\n\n\tpromise: <T,>(\n\t\tpromise: Promise<T> | (() => Promise<T>),\n\t\topts: SileoPromiseOptions<T>,\n\t): Promise<T> => {\n\t\tconst { id } = createToast({\n\t\t\t...opts.loading,\n\t\t\tstate: \"loading\",\n\t\t\tduration: null,\n\t\t});\n\n\t\tconst p = typeof promise === \"function\" ? promise() : promise;\n\n\t\tp.then((data) => {\n\t\t\tif (opts.action) {\n\t\t\t\tconst actionOpts =\n\t\t\t\t\ttypeof opts.action === \"function\" ? opts.action(data) : opts.action;\n\t\t\t\tupdateToast(id, { ...actionOpts, state: \"action\", id });\n\t\t\t} else {\n\t\t\t\tconst successOpts =\n\t\t\t\t\ttypeof opts.success === \"function\"\n\t\t\t\t\t\t? opts.success(data)\n\t\t\t\t\t\t: opts.success;\n\t\t\t\tupdateToast(id, { ...successOpts, state: \"success\", id });\n\t\t\t}\n\t\t}).catch((err) => {\n\t\t\tconst errorOpts =\n\t\t\t\ttypeof opts.error === \"function\" ? opts.error(err) : opts.error;\n\t\t\tupdateToast(id, { ...errorOpts, state: \"error\", id });\n\t\t});\n\n\t\treturn p;\n\t},\n\n\tdismiss: dismissToast,\n\n\tclear: (position?: SileoPosition) =>\n\t\tstore.update((prev) =>\n\t\t\tposition ? prev.filter((t) => t.position !== position) : [],\n\t\t),\n};\n\n/* ------------------------------ Toaster Component ------------------------- */\n\nexport function Toaster({\n\tchildren,\n\tposition = \"top-right\",\n\toffset,\n\toptions,\n}: SileoToasterProps) {\n\tconst [toasts, setToasts] = useState<SileoItem[]>(store.toasts);\n\tconst [activeId, setActiveId] = useState<string>();\n\n\tconst hoverRef = useRef(false);\n\tconst timersRef = useRef(new Map<string, number>());\n\tconst listRef = useRef(toasts);\n\tconst latestRef = useRef<string | undefined>(undefined);\n\tconst handlersCache = useRef(\n\t\tnew Map<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\tenter: MouseEventHandler<HTMLButtonElement>;\n\t\t\t\tleave: MouseEventHandler<HTMLButtonElement>;\n\t\t\t}\n\t\t>(),\n\t);\n\n\tuseEffect(() => {\n\t\tstore.position = position;\n\t\tstore.options = options;\n\t}, [position, options]);\n\n\tconst clearAllTimers = useCallback(() => {\n\t\tfor (const t of timersRef.current.values()) clearTimeout(t);\n\t\ttimersRef.current.clear();\n\t}, []);\n\n\tconst schedule = useCallback((items: SileoItem[]) => {\n\t\tif (hoverRef.current) return;\n\n\t\tfor (const item of items) {\n\t\t\tif (item.exiting) continue;\n\t\t\tconst key = timeoutKey(item);\n\t\t\tif (timersRef.current.has(key)) continue;\n\n\t\t\tconst dur = item.duration ?? DEFAULT_DURATION;\n\t\t\tif (dur === null || dur <= 0) continue;\n\n\t\t\ttimersRef.current.set(\n\t\t\t\tkey,\n\t\t\t\twindow.setTimeout(() => dismissToast(item.id), dur),\n\t\t\t);\n\t\t}\n\t}, []);\n\n\tuseEffect(() => {\n\t\tconst listener: SileoListener = (next) => setToasts(next);\n\t\tstore.listeners.add(listener);\n\t\treturn () => {\n\t\t\tstore.listeners.delete(listener);\n\t\t\tclearAllTimers();\n\t\t};\n\t}, [clearAllTimers]);\n\n\tuseEffect(() => {\n\t\tlistRef.current = toasts;\n\n\t\tconst toastKeys = new Set(toasts.map(timeoutKey));\n\t\tconst toastIds = new Set(toasts.map((t) => t.id));\n\t\tfor (const [key, timer] of timersRef.current) {\n\t\t\tif (!toastKeys.has(key)) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\ttimersRef.current.delete(key);\n\t\t\t}\n\t\t}\n\t\tfor (const id of handlersCache.current.keys()) {\n\t\t\tif (!toastIds.has(id)) handlersCache.current.delete(id);\n\t\t}\n\n\t\tschedule(toasts);\n\t}, [toasts, schedule]);\n\n\tconst handleMouseEnterRef =\n\t\tuseRef<MouseEventHandler<HTMLButtonElement>>(null);\n\tconst handleMouseLeaveRef =\n\t\tuseRef<MouseEventHandler<HTMLButtonElement>>(null);\n\n\thandleMouseEnterRef.current = useCallback<\n\t\tMouseEventHandler<HTMLButtonElement>\n\t>(() => {\n\t\tif (hoverRef.current) return;\n\t\thoverRef.current = true;\n\t\tclearAllTimers();\n\t}, [clearAllTimers]);\n\n\thandleMouseLeaveRef.current = useCallback<\n\t\tMouseEventHandler<HTMLButtonElement>\n\t>(() => {\n\t\tif (!hoverRef.current) return;\n\t\thoverRef.current = false;\n\t\tschedule(listRef.current);\n\t}, [schedule]);\n\n\tconst latest = useMemo(() => {\n\t\tfor (let i = toasts.length - 1; i >= 0; i--) {\n\t\t\tif (!toasts[i].exiting) return toasts[i].id;\n\t\t}\n\t\treturn undefined;\n\t}, [toasts]);\n\n\tuseEffect(() => {\n\t\tlatestRef.current = latest;\n\t\tsetActiveId(latest);\n\t}, [latest]);\n\n\tconst getHandlers = useCallback((toastId: string) => {\n\t\tlet cached = handlersCache.current.get(toastId);\n\t\tif (cached) return cached;\n\n\t\tcached = {\n\t\t\tenter: ((e) => {\n\t\t\t\tsetActiveId((prev) => (prev === toastId ? prev : toastId));\n\t\t\t\thandleMouseEnterRef.current?.(e);\n\t\t\t}) as MouseEventHandler<HTMLButtonElement>,\n\t\t\tleave: ((e) => {\n\t\t\t\tsetActiveId((prev) =>\n\t\t\t\t\tprev === latestRef.current ? prev : latestRef.current,\n\t\t\t\t);\n\t\t\t\thandleMouseLeaveRef.current?.(e);\n\t\t\t}) as MouseEventHandler<HTMLButtonElement>,\n\t\t};\n\n\t\thandlersCache.current.set(toastId, cached);\n\t\treturn cached;\n\t}, []);\n\n\tconst getViewportStyle = useCallback(\n\t\t(pos: SileoPosition): CSSProperties | undefined => {\n\t\t\tif (offset === undefined) return undefined;\n\n\t\t\tconst o =\n\t\t\t\ttypeof offset === \"object\"\n\t\t\t\t\t? offset\n\t\t\t\t\t: { top: offset, right: offset, bottom: offset, left: offset };\n\n\t\t\tconst s: CSSProperties = {};\n\t\t\tconst px = (v: SileoOffsetValue) =>\n\t\t\t\ttypeof v === \"number\" ? `${v}px` : v;\n\n\t\t\tif (pos.startsWith(\"top\") && o.top) s.top = px(o.top);\n\t\t\tif (pos.startsWith(\"bottom\") && o.bottom) s.bottom = px(o.bottom);\n\t\t\tif (pos.endsWith(\"left\") && o.left) s.left = px(o.left);\n\t\t\tif (pos.endsWith(\"right\") && o.right) s.right = px(o.right);\n\n\t\t\treturn s;\n\t\t},\n\t\t[offset],\n\t);\n\n\tconst byPosition = useMemo(() => {\n\t\tconst map = {} as Partial<Record<SileoPosition, SileoItem[]>>;\n\t\tfor (const t of toasts) {\n\t\t\tconst pos = t.position ?? position;\n\t\t\tconst arr = map[pos];\n\t\t\tif (arr) {\n\t\t\t\tarr.push(t);\n\t\t\t} else {\n\t\t\t\tmap[pos] = [t];\n\t\t\t}\n\t\t}\n\t\treturn map;\n\t}, [toasts, position]);\n\n\treturn (\n\t\t<>\n\t\t\t{children}\n\t\t\t{SILEO_POSITIONS.map((pos) => {\n\t\t\t\tconst items = byPosition[pos];\n\t\t\t\tif (!items?.length) return null;\n\n\t\t\t\tconst pill = pillAlign(pos);\n\t\t\t\tconst expand = expandDir(pos);\n\n\t\t\t\treturn (\n\t\t\t\t\t<section\n\t\t\t\t\t\tkey={pos}\n\t\t\t\t\t\tdata-sileo-viewport\n\t\t\t\t\t\tdata-position={pos}\n\t\t\t\t\t\taria-live=\"polite\"\n\t\t\t\t\t\tstyle={getViewportStyle(pos)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{items.map((item) => {\n\t\t\t\t\t\t\tconst h = getHandlers(item.id);\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<Sileo\n\t\t\t\t\t\t\t\t\tkey={item.id}\n\t\t\t\t\t\t\t\t\tid={item.id}\n\t\t\t\t\t\t\t\t\tstate={item.state}\n\t\t\t\t\t\t\t\t\ttitle={item.title}\n\t\t\t\t\t\t\t\t\tdescription={item.description}\n\t\t\t\t\t\t\t\t\tposition={pill}\n\t\t\t\t\t\t\t\t\texpand={expand}\n\t\t\t\t\t\t\t\t\ticon={item.icon}\n\t\t\t\t\t\t\t\t\tfill={item.fill}\n\t\t\t\t\t\t\t\t\tstyles={item.styles}\n\t\t\t\t\t\t\t\t\tbutton={item.button}\n\t\t\t\t\t\t\t\t\troundness={item.roundness}\n\t\t\t\t\t\t\t\t\texiting={item.exiting}\n\t\t\t\t\t\t\t\t\tautoExpandDelayMs={item.autoExpandDelayMs}\n\t\t\t\t\t\t\t\t\tautoCollapseDelayMs={item.autoCollapseDelayMs}\n\t\t\t\t\t\t\t\t\trefreshKey={item.instanceId}\n\t\t\t\t\t\t\t\t\tcanExpand={activeId === undefined || activeId === item.id}\n\t\t\t\t\t\t\t\t\tonMouseEnter={h.enter}\n\t\t\t\t\t\t\t\t\tonMouseLeave={h.leave}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</section>\n\t\t\t\t);\n\t\t\t})}\n\t\t</>\n\t);\n}\n"],"names":[],"mappings":";;AACO,KAAA,UAAA;AACA,UAAA,WAAA;AACP;AACA;AACA;AACA;AACA;AACO,UAAA,WAAA;AACP;AACA;AACA;AACO,cAAA,eAAA;AACA,KAAA,aAAA,WAAA,eAAA;AACA,UAAA,YAAA;AACP;AACA,kBAAA,SAAA;AACA,eAAA,aAAA;AACA;AACA,WAAA,SAAA;AACA,aAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,WAAA;AACA;;AC1BA,KAAA,gBAAA;AACA,KAAA,iBAAA,GAAA,OAAA,CAAA,MAAA,sCAAA,gBAAA;AACO,UAAA,iBAAA;AACP,eAAA,SAAA;AACA,eAAA,aAAA;AACA,aAAA,gBAAA,GAAA,iBAAA;AACA,cAAA,OAAA,CAAA,YAAA;AACA;AACO,UAAA,mBAAA;AACP,aAAA,IAAA,CAAA,YAAA;AACA,aAAA,YAAA,iBAAA,YAAA;AACA,WAAA,YAAA,sBAAA,YAAA;AACA,aAAA,YAAA,iBAAA,YAAA;AACA;AACO,cAAA,KAAA;AACP,iBAAA,YAAA;AACA,oBAAA,YAAA;AACA,kBAAA,YAAA;AACA,oBAAA,YAAA;AACA,iBAAA,YAAA;AACA,mBAAA,YAAA;AACA,0BAAA,OAAA,aAAA,OAAA,YAAA,mBAAA,QAAA,OAAA;AACA;AACA,uBAAA,aAAA;AACA;AACO,iBAAA,OAAA,2CAAA,iBAAA;;;;"}
|
|
1
|
+
{"version":3,"file":"index.d.mts","sources":["../src/types.ts","../src/toast.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nexport type SileoState =\n\t| \"success\"\n\t| \"loading\"\n\t| \"error\"\n\t| \"warning\"\n\t| \"info\"\n\t| \"action\";\n\nexport interface SileoStyles {\n\ttitle?: string;\n\tdescription?: string;\n\tbadge?: string;\n\tbutton?: string;\n}\n\nexport interface SileoButton {\n\ttitle: string;\n\tonClick: () => void;\n}\n\nexport const SILEO_POSITIONS = [\n\t\"top-left\",\n\t\"top-center\",\n\t\"top-right\",\n\t\"bottom-left\",\n\t\"bottom-center\",\n\t\"bottom-right\",\n] as const;\n\nexport type SileoPosition = (typeof SILEO_POSITIONS)[number];\n\nexport interface SileoOptions {\n\ttitle?: string;\n\tdescription?: ReactNode | string;\n\tposition?: SileoPosition;\n\tduration?: number | null;\n\ticon?: ReactNode | null;\n\tstyles?: SileoStyles;\n\tfill?: string;\n\troundness?: number;\n\tautopilot?: boolean | { expand?: number; collapse?: number };\n\tbutton?: SileoButton;\n}\n","import {\n\ttype CSSProperties,\n\ttype MouseEventHandler,\n\ttype ReactNode,\n\tuseCallback,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { Sileo } from \"./sileo\";\nimport {\n\tSILEO_POSITIONS,\n\ttype SileoOptions,\n\ttype SileoPosition,\n\ttype SileoState,\n} from \"./types\";\n\n/* -------------------------------- Constants ------------------------------- */\n\nconst DEFAULT_DURATION = 6000;\nconst EXIT_DURATION = DEFAULT_DURATION * 0.1;\nconst AUTO_EXPAND_DELAY = DEFAULT_DURATION * 0.025;\nconst AUTO_COLLAPSE_DELAY = DEFAULT_DURATION - 2000;\n\nconst pillAlign = (pos: SileoPosition) =>\n\tpos.includes(\"right\") ? \"right\" : pos.includes(\"center\") ? \"center\" : \"left\";\nconst expandDir = (pos: SileoPosition) =>\n\tpos.startsWith(\"top\") ? (\"bottom\" as const) : (\"top\" as const);\n\n/* ---------------------------------- Types --------------------------------- */\n\ninterface InternalSileoOptions extends SileoOptions {\n\tid?: string;\n\tstate?: SileoState;\n}\n\ninterface SileoItem extends InternalSileoOptions {\n\tid: string;\n\tinstanceId: string;\n\texiting?: boolean;\n\tautoExpandDelayMs?: number;\n\tautoCollapseDelayMs?: number;\n}\n\ntype SileoOffsetValue = number | string;\ntype SileoOffsetConfig = Partial<\n\tRecord<\"top\" | \"right\" | \"bottom\" | \"left\", SileoOffsetValue>\n>;\n\nexport interface SileoToasterProps {\n\tchildren?: ReactNode;\n\tposition?: SileoPosition;\n\toffset?: SileoOffsetValue | SileoOffsetConfig;\n\toptions?: Partial<SileoOptions>;\n}\n\n/* ------------------------------ Global State ------------------------------ */\n\ntype SileoListener = (toasts: SileoItem[]) => void;\n\nconst store = {\n\ttoasts: [] as SileoItem[],\n\tlisteners: new Set<SileoListener>(),\n\tposition: \"top-right\" as SileoPosition,\n\toptions: undefined as Partial<SileoOptions> | undefined,\n\n\temit() {\n\t\tfor (const fn of this.listeners) fn(this.toasts);\n\t},\n\n\tupdate(fn: (prev: SileoItem[]) => SileoItem[]) {\n\t\tthis.toasts = fn(this.toasts);\n\t\tthis.emit();\n\t},\n};\n\nlet idCounter = 0;\nconst generateId = () =>\n\t`${++idCounter}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n\nconst timeoutKey = (t: SileoItem) => `${t.id}:${t.instanceId}`;\n\n/* ------------------------------- Toast API -------------------------------- */\n\nconst dismissToast = (id: string) => {\n\tconst item = store.toasts.find((t) => t.id === id);\n\tif (!item || item.exiting) return;\n\n\tstore.update((prev) =>\n\t\tprev.map((t) => (t.id === id ? { ...t, exiting: true } : t)),\n\t);\n\n\tsetTimeout(\n\t\t() => store.update((prev) => prev.filter((t) => t.id !== id)),\n\t\tEXIT_DURATION,\n\t);\n};\n\nconst resolveAutopilot = (\n\topts: InternalSileoOptions,\n\tduration: number | null,\n): { expandDelayMs?: number; collapseDelayMs?: number } => {\n\tif (opts.autopilot === false || !duration || duration <= 0) return {};\n\tconst cfg = typeof opts.autopilot === \"object\" ? opts.autopilot : undefined;\n\tconst clamp = (v: number) => Math.min(duration, Math.max(0, v));\n\treturn {\n\t\texpandDelayMs: clamp(cfg?.expand ?? AUTO_EXPAND_DELAY),\n\t\tcollapseDelayMs: clamp(cfg?.collapse ?? AUTO_COLLAPSE_DELAY),\n\t};\n};\n\nconst mergeOptions = (options: InternalSileoOptions) => ({\n\t...store.options,\n\t...options,\n\tstyles: { ...store.options?.styles, ...options.styles },\n});\n\nconst buildSileoItem = (\n\tmerged: InternalSileoOptions,\n\tid: string,\n\tfallbackPosition?: SileoPosition,\n): SileoItem => {\n\tconst duration = merged.duration ?? DEFAULT_DURATION;\n\tconst auto = resolveAutopilot(merged, duration);\n\treturn {\n\t\t...merged,\n\t\tid,\n\t\tinstanceId: generateId(),\n\t\tposition: merged.position ?? fallbackPosition ?? store.position,\n\t\tautoExpandDelayMs: auto.expandDelayMs,\n\t\tautoCollapseDelayMs: auto.collapseDelayMs,\n\t};\n};\n\nconst createToast = (options: InternalSileoOptions) => {\n\tconst live = store.toasts.filter((t) => !t.exiting);\n\tconst merged = mergeOptions(options);\n\n\tconst id = merged.id ?? \"sileo-default\";\n\tconst prev = live.find((t) => t.id === id);\n\tconst item = buildSileoItem(merged, id, prev?.position);\n\n\tif (prev) {\n\t\tstore.update((p) => p.map((t) => (t.id === id ? item : t)));\n\t} else {\n\t\tstore.update((p) => [...p.filter((t) => t.id !== id), item]);\n\t}\n\treturn { id, duration: merged.duration ?? DEFAULT_DURATION };\n};\n\nconst updateToast = (id: string, options: InternalSileoOptions) => {\n\tconst existing = store.toasts.find((t) => t.id === id);\n\tif (!existing) return;\n\n\tconst item = buildSileoItem(mergeOptions(options), id, existing.position);\n\tstore.update((prev) => prev.map((t) => (t.id === id ? item : t)));\n};\n\nexport interface SileoPromiseOptions<T = unknown> {\n\tloading: Pick<SileoOptions, \"title\" | \"icon\">;\n\tsuccess: SileoOptions | ((data: T) => SileoOptions);\n\terror: SileoOptions | ((err: unknown) => SileoOptions);\n\taction?: SileoOptions | ((data: T) => SileoOptions);\n\tposition?: SileoPosition;\n}\n\nexport const sileo = {\n\tshow: (opts: SileoOptions) => createToast(opts).id,\n\tsuccess: (opts: SileoOptions) =>\n\t\tcreateToast({ ...opts, state: \"success\" }).id,\n\terror: (opts: SileoOptions) => createToast({ ...opts, state: \"error\" }).id,\n\twarning: (opts: SileoOptions) =>\n\t\tcreateToast({ ...opts, state: \"warning\" }).id,\n\tinfo: (opts: SileoOptions) => createToast({ ...opts, state: \"info\" }).id,\n\taction: (opts: SileoOptions) => createToast({ ...opts, state: \"action\" }).id,\n\n\tpromise: <T,>(\n\t\tpromise: Promise<T> | (() => Promise<T>),\n\t\topts: SileoPromiseOptions<T>,\n\t): Promise<T> => {\n\t\tconst { id } = createToast({\n\t\t\t...opts.loading,\n\t\t\tstate: \"loading\",\n\t\t\tduration: null,\n\t\t\tposition: opts.position,\n\t\t});\n\n\t\tconst p = typeof promise === \"function\" ? promise() : promise;\n\n\t\tp.then((data) => {\n\t\t\tif (opts.action) {\n\t\t\t\tconst actionOpts =\n\t\t\t\t\ttypeof opts.action === \"function\" ? opts.action(data) : opts.action;\n\t\t\t\tupdateToast(id, { ...actionOpts, state: \"action\", id });\n\t\t\t} else {\n\t\t\t\tconst successOpts =\n\t\t\t\t\ttypeof opts.success === \"function\"\n\t\t\t\t\t\t? opts.success(data)\n\t\t\t\t\t\t: opts.success;\n\t\t\t\tupdateToast(id, { ...successOpts, state: \"success\", id });\n\t\t\t}\n\t\t}).catch((err) => {\n\t\t\tconst errorOpts =\n\t\t\t\ttypeof opts.error === \"function\" ? opts.error(err) : opts.error;\n\t\t\tupdateToast(id, { ...errorOpts, state: \"error\", id });\n\t\t});\n\n\t\treturn p;\n\t},\n\n\tdismiss: dismissToast,\n\n\tclear: (position?: SileoPosition) =>\n\t\tstore.update((prev) =>\n\t\t\tposition ? prev.filter((t) => t.position !== position) : [],\n\t\t),\n};\n\n/* ------------------------------ Toaster Component ------------------------- */\n\nexport function Toaster({\n\tchildren,\n\tposition = \"top-right\",\n\toffset,\n\toptions,\n}: SileoToasterProps) {\n\tconst [toasts, setToasts] = useState<SileoItem[]>(store.toasts);\n\tconst [activeId, setActiveId] = useState<string>();\n\n\tconst hoverRef = useRef(false);\n\tconst timersRef = useRef(new Map<string, number>());\n\tconst listRef = useRef(toasts);\n\tconst latestRef = useRef<string | undefined>(undefined);\n\tconst handlersCache = useRef(\n\t\tnew Map<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\tenter: MouseEventHandler<HTMLButtonElement>;\n\t\t\t\tleave: MouseEventHandler<HTMLButtonElement>;\n\t\t\t\tdismiss: () => void;\n\t\t\t}\n\t\t>(),\n\t);\n\n\tuseEffect(() => {\n\t\tstore.position = position;\n\t\tstore.options = options;\n\t}, [position, options]);\n\n\tconst clearAllTimers = useCallback(() => {\n\t\tfor (const t of timersRef.current.values()) clearTimeout(t);\n\t\ttimersRef.current.clear();\n\t}, []);\n\n\tconst schedule = useCallback((items: SileoItem[]) => {\n\t\tif (hoverRef.current) return;\n\n\t\tfor (const item of items) {\n\t\t\tif (item.exiting) continue;\n\t\t\tconst key = timeoutKey(item);\n\t\t\tif (timersRef.current.has(key)) continue;\n\n\t\t\tconst dur = item.duration ?? DEFAULT_DURATION;\n\t\t\tif (dur === null || dur <= 0) continue;\n\n\t\t\ttimersRef.current.set(\n\t\t\t\tkey,\n\t\t\t\twindow.setTimeout(() => dismissToast(item.id), dur),\n\t\t\t);\n\t\t}\n\t}, []);\n\n\tuseEffect(() => {\n\t\tconst listener: SileoListener = (next) => setToasts(next);\n\t\tstore.listeners.add(listener);\n\t\treturn () => {\n\t\t\tstore.listeners.delete(listener);\n\t\t\tclearAllTimers();\n\t\t};\n\t}, [clearAllTimers]);\n\n\tuseEffect(() => {\n\t\tlistRef.current = toasts;\n\n\t\tconst toastKeys = new Set(toasts.map(timeoutKey));\n\t\tconst toastIds = new Set(toasts.map((t) => t.id));\n\t\tfor (const [key, timer] of timersRef.current) {\n\t\t\tif (!toastKeys.has(key)) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\ttimersRef.current.delete(key);\n\t\t\t}\n\t\t}\n\t\tfor (const id of handlersCache.current.keys()) {\n\t\t\tif (!toastIds.has(id)) handlersCache.current.delete(id);\n\t\t}\n\n\t\tschedule(toasts);\n\t}, [toasts, schedule]);\n\n\tconst handleMouseEnterRef =\n\t\tuseRef<MouseEventHandler<HTMLButtonElement>>(null);\n\tconst handleMouseLeaveRef =\n\t\tuseRef<MouseEventHandler<HTMLButtonElement>>(null);\n\n\thandleMouseEnterRef.current = useCallback<\n\t\tMouseEventHandler<HTMLButtonElement>\n\t>(() => {\n\t\tif (hoverRef.current) return;\n\t\thoverRef.current = true;\n\t\tclearAllTimers();\n\t}, [clearAllTimers]);\n\n\thandleMouseLeaveRef.current = useCallback<\n\t\tMouseEventHandler<HTMLButtonElement>\n\t>(() => {\n\t\tif (!hoverRef.current) return;\n\t\thoverRef.current = false;\n\t\tschedule(listRef.current);\n\t}, [schedule]);\n\n\tconst latest = useMemo(() => {\n\t\tfor (let i = toasts.length - 1; i >= 0; i--) {\n\t\t\tif (!toasts[i].exiting) return toasts[i].id;\n\t\t}\n\t\treturn undefined;\n\t}, [toasts]);\n\n\tuseEffect(() => {\n\t\tlatestRef.current = latest;\n\t\tsetActiveId(latest);\n\t}, [latest]);\n\n\tconst getHandlers = useCallback((toastId: string) => {\n\t\tlet cached = handlersCache.current.get(toastId);\n\t\tif (cached) return cached;\n\n\t\tcached = {\n\t\t\tenter: ((e) => {\n\t\t\t\tsetActiveId((prev) => (prev === toastId ? prev : toastId));\n\t\t\t\thandleMouseEnterRef.current?.(e);\n\t\t\t}) as MouseEventHandler<HTMLButtonElement>,\n\t\t\tleave: ((e) => {\n\t\t\t\tsetActiveId((prev) =>\n\t\t\t\t\tprev === latestRef.current ? prev : latestRef.current,\n\t\t\t\t);\n\t\t\t\thandleMouseLeaveRef.current?.(e);\n\t\t\t}) as MouseEventHandler<HTMLButtonElement>,\n\t\t\tdismiss: () => dismissToast(toastId),\n\t\t};\n\n\t\thandlersCache.current.set(toastId, cached);\n\t\treturn cached;\n\t}, []);\n\n\tconst getViewportStyle = useCallback(\n\t\t(pos: SileoPosition): CSSProperties | undefined => {\n\t\t\tif (offset === undefined) return undefined;\n\n\t\t\tconst o =\n\t\t\t\ttypeof offset === \"object\"\n\t\t\t\t\t? offset\n\t\t\t\t\t: { top: offset, right: offset, bottom: offset, left: offset };\n\n\t\t\tconst s: CSSProperties = {};\n\t\t\tconst px = (v: SileoOffsetValue) =>\n\t\t\t\ttypeof v === \"number\" ? `${v}px` : v;\n\n\t\t\tif (pos.startsWith(\"top\") && o.top) s.top = px(o.top);\n\t\t\tif (pos.startsWith(\"bottom\") && o.bottom) s.bottom = px(o.bottom);\n\t\t\tif (pos.endsWith(\"left\") && o.left) s.left = px(o.left);\n\t\t\tif (pos.endsWith(\"right\") && o.right) s.right = px(o.right);\n\n\t\t\treturn s;\n\t\t},\n\t\t[offset],\n\t);\n\n\tconst byPosition = useMemo(() => {\n\t\tconst map = {} as Partial<Record<SileoPosition, SileoItem[]>>;\n\t\tfor (const t of toasts) {\n\t\t\tconst pos = t.position ?? position;\n\t\t\tconst arr = map[pos];\n\t\t\tif (arr) {\n\t\t\t\tarr.push(t);\n\t\t\t} else {\n\t\t\t\tmap[pos] = [t];\n\t\t\t}\n\t\t}\n\t\treturn map;\n\t}, [toasts, position]);\n\n\treturn (\n\t\t<>\n\t\t\t{children}\n\t\t\t{SILEO_POSITIONS.map((pos) => {\n\t\t\t\tconst items = byPosition[pos];\n\t\t\t\tif (!items?.length) return null;\n\n\t\t\t\tconst pill = pillAlign(pos);\n\t\t\t\tconst expand = expandDir(pos);\n\n\t\t\t\treturn (\n\t\t\t\t\t<section\n\t\t\t\t\t\tkey={pos}\n\t\t\t\t\t\tdata-sileo-viewport\n\t\t\t\t\t\tdata-position={pos}\n\t\t\t\t\t\taria-live=\"polite\"\n\t\t\t\t\t\tstyle={getViewportStyle(pos)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{items.map((item) => {\n\t\t\t\t\t\t\tconst h = getHandlers(item.id);\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<Sileo\n\t\t\t\t\t\t\t\t\tkey={item.id}\n\t\t\t\t\t\t\t\t\tid={item.id}\n\t\t\t\t\t\t\t\t\tstate={item.state}\n\t\t\t\t\t\t\t\t\ttitle={item.title}\n\t\t\t\t\t\t\t\t\tdescription={item.description}\n\t\t\t\t\t\t\t\t\tposition={pill}\n\t\t\t\t\t\t\t\t\texpand={expand}\n\t\t\t\t\t\t\t\t\ticon={item.icon}\n\t\t\t\t\t\t\t\t\tfill={item.fill}\n\t\t\t\t\t\t\t\t\tstyles={item.styles}\n\t\t\t\t\t\t\t\t\tbutton={item.button}\n\t\t\t\t\t\t\t\t\troundness={item.roundness}\n\t\t\t\t\t\t\t\t\texiting={item.exiting}\n\t\t\t\t\t\t\t\t\tautoExpandDelayMs={item.autoExpandDelayMs}\n\t\t\t\t\t\t\t\t\tautoCollapseDelayMs={item.autoCollapseDelayMs}\n\t\t\t\t\t\t\t\t\trefreshKey={item.instanceId}\n\t\t\t\t\t\t\t\t\tcanExpand={activeId === undefined || activeId === item.id}\n\t\t\t\t\t\t\t\t\tonMouseEnter={h.enter}\n\t\t\t\t\t\t\t\t\tonMouseLeave={h.leave}\n\t\t\t\t\t\t\t\t\tonDismiss={h.dismiss}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</section>\n\t\t\t\t);\n\t\t\t})}\n\t\t</>\n\t);\n}\n"],"names":[],"mappings":";;AACO,KAAA,UAAA;AACA,UAAA,WAAA;AACP;AACA;AACA;AACA;AACA;AACO,UAAA,WAAA;AACP;AACA;AACA;AACO,cAAA,eAAA;AACA,KAAA,aAAA,WAAA,eAAA;AACA,UAAA,YAAA;AACP;AACA,kBAAA,SAAA;AACA,eAAA,aAAA;AACA;AACA,WAAA,SAAA;AACA,aAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,WAAA;AACA;;AC1BA,KAAA,gBAAA;AACA,KAAA,iBAAA,GAAA,OAAA,CAAA,MAAA,sCAAA,gBAAA;AACO,UAAA,iBAAA;AACP,eAAA,SAAA;AACA,eAAA,aAAA;AACA,aAAA,gBAAA,GAAA,iBAAA;AACA,cAAA,OAAA,CAAA,YAAA;AACA;AACO,UAAA,mBAAA;AACP,aAAA,IAAA,CAAA,YAAA;AACA,aAAA,YAAA,iBAAA,YAAA;AACA,WAAA,YAAA,sBAAA,YAAA;AACA,aAAA,YAAA,iBAAA,YAAA;AACA,eAAA,aAAA;AACA;AACO,cAAA,KAAA;AACP,iBAAA,YAAA;AACA,oBAAA,YAAA;AACA,kBAAA,YAAA;AACA,oBAAA,YAAA;AACA,iBAAA,YAAA;AACA,mBAAA,YAAA;AACA,0BAAA,OAAA,aAAA,OAAA,YAAA,mBAAA,QAAA,OAAA;AACA;AACA,uBAAA,aAAA;AACA;AACO,iBAAA,OAAA,2CAAA,iBAAA;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ interface SileoPromiseOptions<T = unknown> {
|
|
|
42
42
|
success: SileoOptions | ((data: T) => SileoOptions);
|
|
43
43
|
error: SileoOptions | ((err: unknown) => SileoOptions);
|
|
44
44
|
action?: SileoOptions | ((data: T) => SileoOptions);
|
|
45
|
+
position?: SileoPosition;
|
|
45
46
|
}
|
|
46
47
|
declare const sileo: {
|
|
47
48
|
show: (opts: SileoOptions) => string;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sources":["../src/types.ts","../src/toast.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nexport type SileoState =\n\t| \"success\"\n\t| \"loading\"\n\t| \"error\"\n\t| \"warning\"\n\t| \"info\"\n\t| \"action\";\n\nexport interface SileoStyles {\n\ttitle?: string;\n\tdescription?: string;\n\tbadge?: string;\n\tbutton?: string;\n}\n\nexport interface SileoButton {\n\ttitle: string;\n\tonClick: () => void;\n}\n\nexport const SILEO_POSITIONS = [\n\t\"top-left\",\n\t\"top-center\",\n\t\"top-right\",\n\t\"bottom-left\",\n\t\"bottom-center\",\n\t\"bottom-right\",\n] as const;\n\nexport type SileoPosition = (typeof SILEO_POSITIONS)[number];\n\nexport interface SileoOptions {\n\ttitle?: string;\n\tdescription?: ReactNode | string;\n\tposition?: SileoPosition;\n\tduration?: number | null;\n\ticon?: ReactNode | null;\n\tstyles?: SileoStyles;\n\tfill?: string;\n\troundness?: number;\n\tautopilot?: boolean | { expand?: number; collapse?: number };\n\tbutton?: SileoButton;\n}\n","import {\n\ttype CSSProperties,\n\ttype MouseEventHandler,\n\ttype ReactNode,\n\tuseCallback,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { Sileo } from \"./sileo\";\nimport {\n\tSILEO_POSITIONS,\n\ttype SileoOptions,\n\ttype SileoPosition,\n\ttype SileoState,\n} from \"./types\";\n\n/* -------------------------------- Constants ------------------------------- */\n\nconst DEFAULT_DURATION = 6000;\nconst EXIT_DURATION = DEFAULT_DURATION * 0.1;\nconst AUTO_EXPAND_DELAY = DEFAULT_DURATION * 0.025;\nconst AUTO_COLLAPSE_DELAY = DEFAULT_DURATION - 2000;\n\nconst pillAlign = (pos: SileoPosition) =>\n\tpos.includes(\"right\") ? \"right\" : pos.includes(\"center\") ? \"center\" : \"left\";\nconst expandDir = (pos: SileoPosition) =>\n\tpos.startsWith(\"top\") ? (\"bottom\" as const) : (\"top\" as const);\n\n/* ---------------------------------- Types --------------------------------- */\n\ninterface InternalSileoOptions extends SileoOptions {\n\tid?: string;\n\tstate?: SileoState;\n}\n\ninterface SileoItem extends InternalSileoOptions {\n\tid: string;\n\tinstanceId: string;\n\texiting?: boolean;\n\tautoExpandDelayMs?: number;\n\tautoCollapseDelayMs?: number;\n}\n\ntype SileoOffsetValue = number | string;\ntype SileoOffsetConfig = Partial<\n\tRecord<\"top\" | \"right\" | \"bottom\" | \"left\", SileoOffsetValue>\n>;\n\nexport interface SileoToasterProps {\n\tchildren?: ReactNode;\n\tposition?: SileoPosition;\n\toffset?: SileoOffsetValue | SileoOffsetConfig;\n\toptions?: Partial<SileoOptions>;\n}\n\n/* ------------------------------ Global State ------------------------------ */\n\ntype SileoListener = (toasts: SileoItem[]) => void;\n\nconst store = {\n\ttoasts: [] as SileoItem[],\n\tlisteners: new Set<SileoListener>(),\n\tposition: \"top-right\" as SileoPosition,\n\toptions: undefined as Partial<SileoOptions> | undefined,\n\n\temit() {\n\t\tfor (const fn of this.listeners) fn(this.toasts);\n\t},\n\n\tupdate(fn: (prev: SileoItem[]) => SileoItem[]) {\n\t\tthis.toasts = fn(this.toasts);\n\t\tthis.emit();\n\t},\n};\n\nlet idCounter = 0;\nconst generateId = () =>\n\t`${++idCounter}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n\nconst timeoutKey = (t: SileoItem) => `${t.id}:${t.instanceId}`;\n\n/* ------------------------------- Toast API -------------------------------- */\n\nconst dismissToast = (id: string) => {\n\tconst item = store.toasts.find((t) => t.id === id);\n\tif (!item || item.exiting) return;\n\n\tstore.update((prev) =>\n\t\tprev.map((t) => (t.id === id ? { ...t, exiting: true } : t)),\n\t);\n\n\tsetTimeout(\n\t\t() => store.update((prev) => prev.filter((t) => t.id !== id)),\n\t\tEXIT_DURATION,\n\t);\n};\n\nconst resolveAutopilot = (\n\topts: InternalSileoOptions,\n\tduration: number | null,\n): { expandDelayMs?: number; collapseDelayMs?: number } => {\n\tif (opts.autopilot === false || !duration || duration <= 0) return {};\n\tconst cfg = typeof opts.autopilot === \"object\" ? opts.autopilot : undefined;\n\tconst clamp = (v: number) => Math.min(duration, Math.max(0, v));\n\treturn {\n\t\texpandDelayMs: clamp(cfg?.expand ?? AUTO_EXPAND_DELAY),\n\t\tcollapseDelayMs: clamp(cfg?.collapse ?? AUTO_COLLAPSE_DELAY),\n\t};\n};\n\nconst mergeOptions = (options: InternalSileoOptions) => ({\n\t...store.options,\n\t...options,\n\tstyles: { ...store.options?.styles, ...options.styles },\n});\n\nconst buildSileoItem = (\n\tmerged: InternalSileoOptions,\n\tid: string,\n\tfallbackPosition?: SileoPosition,\n): SileoItem => {\n\tconst duration = merged.duration ?? DEFAULT_DURATION;\n\tconst auto = resolveAutopilot(merged, duration);\n\treturn {\n\t\t...merged,\n\t\tid,\n\t\tinstanceId: generateId(),\n\t\tposition: merged.position ?? fallbackPosition ?? store.position,\n\t\tautoExpandDelayMs: auto.expandDelayMs,\n\t\tautoCollapseDelayMs: auto.collapseDelayMs,\n\t};\n};\n\nconst createToast = (options: InternalSileoOptions) => {\n\tconst live = store.toasts.filter((t) => !t.exiting);\n\tconst merged = mergeOptions(options);\n\n\tconst id = merged.id ?? \"sileo-default\";\n\tconst prev = live.find((t) => t.id === id);\n\tconst item = buildSileoItem(merged, id, prev?.position);\n\n\tif (prev) {\n\t\tstore.update((p) => p.map((t) => (t.id === id ? item : t)));\n\t} else {\n\t\tstore.update((p) => [...p, item]);\n\t}\n\treturn { id, duration: merged.duration ?? DEFAULT_DURATION };\n};\n\nconst updateToast = (id: string, options: InternalSileoOptions) => {\n\tconst existing = store.toasts.find((t) => t.id === id);\n\tif (!existing) return;\n\n\tconst item = buildSileoItem(mergeOptions(options), id, existing.position);\n\tstore.update((prev) => prev.map((t) => (t.id === id ? item : t)));\n};\n\nexport interface SileoPromiseOptions<T = unknown> {\n\tloading: Pick<SileoOptions, \"title\" | \"icon\">;\n\tsuccess: SileoOptions | ((data: T) => SileoOptions);\n\terror: SileoOptions | ((err: unknown) => SileoOptions);\n\taction?: SileoOptions | ((data: T) => SileoOptions);\n}\n\nexport const sileo = {\n\tshow: (opts: SileoOptions) => createToast(opts).id,\n\tsuccess: (opts: SileoOptions) =>\n\t\tcreateToast({ ...opts, state: \"success\" }).id,\n\terror: (opts: SileoOptions) => createToast({ ...opts, state: \"error\" }).id,\n\twarning: (opts: SileoOptions) =>\n\t\tcreateToast({ ...opts, state: \"warning\" }).id,\n\tinfo: (opts: SileoOptions) => createToast({ ...opts, state: \"info\" }).id,\n\taction: (opts: SileoOptions) => createToast({ ...opts, state: \"action\" }).id,\n\n\tpromise: <T,>(\n\t\tpromise: Promise<T> | (() => Promise<T>),\n\t\topts: SileoPromiseOptions<T>,\n\t): Promise<T> => {\n\t\tconst { id } = createToast({\n\t\t\t...opts.loading,\n\t\t\tstate: \"loading\",\n\t\t\tduration: null,\n\t\t});\n\n\t\tconst p = typeof promise === \"function\" ? promise() : promise;\n\n\t\tp.then((data) => {\n\t\t\tif (opts.action) {\n\t\t\t\tconst actionOpts =\n\t\t\t\t\ttypeof opts.action === \"function\" ? opts.action(data) : opts.action;\n\t\t\t\tupdateToast(id, { ...actionOpts, state: \"action\", id });\n\t\t\t} else {\n\t\t\t\tconst successOpts =\n\t\t\t\t\ttypeof opts.success === \"function\"\n\t\t\t\t\t\t? opts.success(data)\n\t\t\t\t\t\t: opts.success;\n\t\t\t\tupdateToast(id, { ...successOpts, state: \"success\", id });\n\t\t\t}\n\t\t}).catch((err) => {\n\t\t\tconst errorOpts =\n\t\t\t\ttypeof opts.error === \"function\" ? opts.error(err) : opts.error;\n\t\t\tupdateToast(id, { ...errorOpts, state: \"error\", id });\n\t\t});\n\n\t\treturn p;\n\t},\n\n\tdismiss: dismissToast,\n\n\tclear: (position?: SileoPosition) =>\n\t\tstore.update((prev) =>\n\t\t\tposition ? prev.filter((t) => t.position !== position) : [],\n\t\t),\n};\n\n/* ------------------------------ Toaster Component ------------------------- */\n\nexport function Toaster({\n\tchildren,\n\tposition = \"top-right\",\n\toffset,\n\toptions,\n}: SileoToasterProps) {\n\tconst [toasts, setToasts] = useState<SileoItem[]>(store.toasts);\n\tconst [activeId, setActiveId] = useState<string>();\n\n\tconst hoverRef = useRef(false);\n\tconst timersRef = useRef(new Map<string, number>());\n\tconst listRef = useRef(toasts);\n\tconst latestRef = useRef<string | undefined>(undefined);\n\tconst handlersCache = useRef(\n\t\tnew Map<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\tenter: MouseEventHandler<HTMLButtonElement>;\n\t\t\t\tleave: MouseEventHandler<HTMLButtonElement>;\n\t\t\t}\n\t\t>(),\n\t);\n\n\tuseEffect(() => {\n\t\tstore.position = position;\n\t\tstore.options = options;\n\t}, [position, options]);\n\n\tconst clearAllTimers = useCallback(() => {\n\t\tfor (const t of timersRef.current.values()) clearTimeout(t);\n\t\ttimersRef.current.clear();\n\t}, []);\n\n\tconst schedule = useCallback((items: SileoItem[]) => {\n\t\tif (hoverRef.current) return;\n\n\t\tfor (const item of items) {\n\t\t\tif (item.exiting) continue;\n\t\t\tconst key = timeoutKey(item);\n\t\t\tif (timersRef.current.has(key)) continue;\n\n\t\t\tconst dur = item.duration ?? DEFAULT_DURATION;\n\t\t\tif (dur === null || dur <= 0) continue;\n\n\t\t\ttimersRef.current.set(\n\t\t\t\tkey,\n\t\t\t\twindow.setTimeout(() => dismissToast(item.id), dur),\n\t\t\t);\n\t\t}\n\t}, []);\n\n\tuseEffect(() => {\n\t\tconst listener: SileoListener = (next) => setToasts(next);\n\t\tstore.listeners.add(listener);\n\t\treturn () => {\n\t\t\tstore.listeners.delete(listener);\n\t\t\tclearAllTimers();\n\t\t};\n\t}, [clearAllTimers]);\n\n\tuseEffect(() => {\n\t\tlistRef.current = toasts;\n\n\t\tconst toastKeys = new Set(toasts.map(timeoutKey));\n\t\tconst toastIds = new Set(toasts.map((t) => t.id));\n\t\tfor (const [key, timer] of timersRef.current) {\n\t\t\tif (!toastKeys.has(key)) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\ttimersRef.current.delete(key);\n\t\t\t}\n\t\t}\n\t\tfor (const id of handlersCache.current.keys()) {\n\t\t\tif (!toastIds.has(id)) handlersCache.current.delete(id);\n\t\t}\n\n\t\tschedule(toasts);\n\t}, [toasts, schedule]);\n\n\tconst handleMouseEnterRef =\n\t\tuseRef<MouseEventHandler<HTMLButtonElement>>(null);\n\tconst handleMouseLeaveRef =\n\t\tuseRef<MouseEventHandler<HTMLButtonElement>>(null);\n\n\thandleMouseEnterRef.current = useCallback<\n\t\tMouseEventHandler<HTMLButtonElement>\n\t>(() => {\n\t\tif (hoverRef.current) return;\n\t\thoverRef.current = true;\n\t\tclearAllTimers();\n\t}, [clearAllTimers]);\n\n\thandleMouseLeaveRef.current = useCallback<\n\t\tMouseEventHandler<HTMLButtonElement>\n\t>(() => {\n\t\tif (!hoverRef.current) return;\n\t\thoverRef.current = false;\n\t\tschedule(listRef.current);\n\t}, [schedule]);\n\n\tconst latest = useMemo(() => {\n\t\tfor (let i = toasts.length - 1; i >= 0; i--) {\n\t\t\tif (!toasts[i].exiting) return toasts[i].id;\n\t\t}\n\t\treturn undefined;\n\t}, [toasts]);\n\n\tuseEffect(() => {\n\t\tlatestRef.current = latest;\n\t\tsetActiveId(latest);\n\t}, [latest]);\n\n\tconst getHandlers = useCallback((toastId: string) => {\n\t\tlet cached = handlersCache.current.get(toastId);\n\t\tif (cached) return cached;\n\n\t\tcached = {\n\t\t\tenter: ((e) => {\n\t\t\t\tsetActiveId((prev) => (prev === toastId ? prev : toastId));\n\t\t\t\thandleMouseEnterRef.current?.(e);\n\t\t\t}) as MouseEventHandler<HTMLButtonElement>,\n\t\t\tleave: ((e) => {\n\t\t\t\tsetActiveId((prev) =>\n\t\t\t\t\tprev === latestRef.current ? prev : latestRef.current,\n\t\t\t\t);\n\t\t\t\thandleMouseLeaveRef.current?.(e);\n\t\t\t}) as MouseEventHandler<HTMLButtonElement>,\n\t\t};\n\n\t\thandlersCache.current.set(toastId, cached);\n\t\treturn cached;\n\t}, []);\n\n\tconst getViewportStyle = useCallback(\n\t\t(pos: SileoPosition): CSSProperties | undefined => {\n\t\t\tif (offset === undefined) return undefined;\n\n\t\t\tconst o =\n\t\t\t\ttypeof offset === \"object\"\n\t\t\t\t\t? offset\n\t\t\t\t\t: { top: offset, right: offset, bottom: offset, left: offset };\n\n\t\t\tconst s: CSSProperties = {};\n\t\t\tconst px = (v: SileoOffsetValue) =>\n\t\t\t\ttypeof v === \"number\" ? `${v}px` : v;\n\n\t\t\tif (pos.startsWith(\"top\") && o.top) s.top = px(o.top);\n\t\t\tif (pos.startsWith(\"bottom\") && o.bottom) s.bottom = px(o.bottom);\n\t\t\tif (pos.endsWith(\"left\") && o.left) s.left = px(o.left);\n\t\t\tif (pos.endsWith(\"right\") && o.right) s.right = px(o.right);\n\n\t\t\treturn s;\n\t\t},\n\t\t[offset],\n\t);\n\n\tconst byPosition = useMemo(() => {\n\t\tconst map = {} as Partial<Record<SileoPosition, SileoItem[]>>;\n\t\tfor (const t of toasts) {\n\t\t\tconst pos = t.position ?? position;\n\t\t\tconst arr = map[pos];\n\t\t\tif (arr) {\n\t\t\t\tarr.push(t);\n\t\t\t} else {\n\t\t\t\tmap[pos] = [t];\n\t\t\t}\n\t\t}\n\t\treturn map;\n\t}, [toasts, position]);\n\n\treturn (\n\t\t<>\n\t\t\t{children}\n\t\t\t{SILEO_POSITIONS.map((pos) => {\n\t\t\t\tconst items = byPosition[pos];\n\t\t\t\tif (!items?.length) return null;\n\n\t\t\t\tconst pill = pillAlign(pos);\n\t\t\t\tconst expand = expandDir(pos);\n\n\t\t\t\treturn (\n\t\t\t\t\t<section\n\t\t\t\t\t\tkey={pos}\n\t\t\t\t\t\tdata-sileo-viewport\n\t\t\t\t\t\tdata-position={pos}\n\t\t\t\t\t\taria-live=\"polite\"\n\t\t\t\t\t\tstyle={getViewportStyle(pos)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{items.map((item) => {\n\t\t\t\t\t\t\tconst h = getHandlers(item.id);\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<Sileo\n\t\t\t\t\t\t\t\t\tkey={item.id}\n\t\t\t\t\t\t\t\t\tid={item.id}\n\t\t\t\t\t\t\t\t\tstate={item.state}\n\t\t\t\t\t\t\t\t\ttitle={item.title}\n\t\t\t\t\t\t\t\t\tdescription={item.description}\n\t\t\t\t\t\t\t\t\tposition={pill}\n\t\t\t\t\t\t\t\t\texpand={expand}\n\t\t\t\t\t\t\t\t\ticon={item.icon}\n\t\t\t\t\t\t\t\t\tfill={item.fill}\n\t\t\t\t\t\t\t\t\tstyles={item.styles}\n\t\t\t\t\t\t\t\t\tbutton={item.button}\n\t\t\t\t\t\t\t\t\troundness={item.roundness}\n\t\t\t\t\t\t\t\t\texiting={item.exiting}\n\t\t\t\t\t\t\t\t\tautoExpandDelayMs={item.autoExpandDelayMs}\n\t\t\t\t\t\t\t\t\tautoCollapseDelayMs={item.autoCollapseDelayMs}\n\t\t\t\t\t\t\t\t\trefreshKey={item.instanceId}\n\t\t\t\t\t\t\t\t\tcanExpand={activeId === undefined || activeId === item.id}\n\t\t\t\t\t\t\t\t\tonMouseEnter={h.enter}\n\t\t\t\t\t\t\t\t\tonMouseLeave={h.leave}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</section>\n\t\t\t\t);\n\t\t\t})}\n\t\t</>\n\t);\n}\n"],"names":[],"mappings":";;AACO,KAAA,UAAA;AACA,UAAA,WAAA;AACP;AACA;AACA;AACA;AACA;AACO,UAAA,WAAA;AACP;AACA;AACA;AACO,cAAA,eAAA;AACA,KAAA,aAAA,WAAA,eAAA;AACA,UAAA,YAAA;AACP;AACA,kBAAA,SAAA;AACA,eAAA,aAAA;AACA;AACA,WAAA,SAAA;AACA,aAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,WAAA;AACA;;AC1BA,KAAA,gBAAA;AACA,KAAA,iBAAA,GAAA,OAAA,CAAA,MAAA,sCAAA,gBAAA;AACO,UAAA,iBAAA;AACP,eAAA,SAAA;AACA,eAAA,aAAA;AACA,aAAA,gBAAA,GAAA,iBAAA;AACA,cAAA,OAAA,CAAA,YAAA;AACA;AACO,UAAA,mBAAA;AACP,aAAA,IAAA,CAAA,YAAA;AACA,aAAA,YAAA,iBAAA,YAAA;AACA,WAAA,YAAA,sBAAA,YAAA;AACA,aAAA,YAAA,iBAAA,YAAA;AACA;AACO,cAAA,KAAA;AACP,iBAAA,YAAA;AACA,oBAAA,YAAA;AACA,kBAAA,YAAA;AACA,oBAAA,YAAA;AACA,iBAAA,YAAA;AACA,mBAAA,YAAA;AACA,0BAAA,OAAA,aAAA,OAAA,YAAA,mBAAA,QAAA,OAAA;AACA;AACA,uBAAA,aAAA;AACA;AACO,iBAAA,OAAA,2CAAA,iBAAA;;;;"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sources":["../src/types.ts","../src/toast.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nexport type SileoState =\n\t| \"success\"\n\t| \"loading\"\n\t| \"error\"\n\t| \"warning\"\n\t| \"info\"\n\t| \"action\";\n\nexport interface SileoStyles {\n\ttitle?: string;\n\tdescription?: string;\n\tbadge?: string;\n\tbutton?: string;\n}\n\nexport interface SileoButton {\n\ttitle: string;\n\tonClick: () => void;\n}\n\nexport const SILEO_POSITIONS = [\n\t\"top-left\",\n\t\"top-center\",\n\t\"top-right\",\n\t\"bottom-left\",\n\t\"bottom-center\",\n\t\"bottom-right\",\n] as const;\n\nexport type SileoPosition = (typeof SILEO_POSITIONS)[number];\n\nexport interface SileoOptions {\n\ttitle?: string;\n\tdescription?: ReactNode | string;\n\tposition?: SileoPosition;\n\tduration?: number | null;\n\ticon?: ReactNode | null;\n\tstyles?: SileoStyles;\n\tfill?: string;\n\troundness?: number;\n\tautopilot?: boolean | { expand?: number; collapse?: number };\n\tbutton?: SileoButton;\n}\n","import {\n\ttype CSSProperties,\n\ttype MouseEventHandler,\n\ttype ReactNode,\n\tuseCallback,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { Sileo } from \"./sileo\";\nimport {\n\tSILEO_POSITIONS,\n\ttype SileoOptions,\n\ttype SileoPosition,\n\ttype SileoState,\n} from \"./types\";\n\n/* -------------------------------- Constants ------------------------------- */\n\nconst DEFAULT_DURATION = 6000;\nconst EXIT_DURATION = DEFAULT_DURATION * 0.1;\nconst AUTO_EXPAND_DELAY = DEFAULT_DURATION * 0.025;\nconst AUTO_COLLAPSE_DELAY = DEFAULT_DURATION - 2000;\n\nconst pillAlign = (pos: SileoPosition) =>\n\tpos.includes(\"right\") ? \"right\" : pos.includes(\"center\") ? \"center\" : \"left\";\nconst expandDir = (pos: SileoPosition) =>\n\tpos.startsWith(\"top\") ? (\"bottom\" as const) : (\"top\" as const);\n\n/* ---------------------------------- Types --------------------------------- */\n\ninterface InternalSileoOptions extends SileoOptions {\n\tid?: string;\n\tstate?: SileoState;\n}\n\ninterface SileoItem extends InternalSileoOptions {\n\tid: string;\n\tinstanceId: string;\n\texiting?: boolean;\n\tautoExpandDelayMs?: number;\n\tautoCollapseDelayMs?: number;\n}\n\ntype SileoOffsetValue = number | string;\ntype SileoOffsetConfig = Partial<\n\tRecord<\"top\" | \"right\" | \"bottom\" | \"left\", SileoOffsetValue>\n>;\n\nexport interface SileoToasterProps {\n\tchildren?: ReactNode;\n\tposition?: SileoPosition;\n\toffset?: SileoOffsetValue | SileoOffsetConfig;\n\toptions?: Partial<SileoOptions>;\n}\n\n/* ------------------------------ Global State ------------------------------ */\n\ntype SileoListener = (toasts: SileoItem[]) => void;\n\nconst store = {\n\ttoasts: [] as SileoItem[],\n\tlisteners: new Set<SileoListener>(),\n\tposition: \"top-right\" as SileoPosition,\n\toptions: undefined as Partial<SileoOptions> | undefined,\n\n\temit() {\n\t\tfor (const fn of this.listeners) fn(this.toasts);\n\t},\n\n\tupdate(fn: (prev: SileoItem[]) => SileoItem[]) {\n\t\tthis.toasts = fn(this.toasts);\n\t\tthis.emit();\n\t},\n};\n\nlet idCounter = 0;\nconst generateId = () =>\n\t`${++idCounter}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n\nconst timeoutKey = (t: SileoItem) => `${t.id}:${t.instanceId}`;\n\n/* ------------------------------- Toast API -------------------------------- */\n\nconst dismissToast = (id: string) => {\n\tconst item = store.toasts.find((t) => t.id === id);\n\tif (!item || item.exiting) return;\n\n\tstore.update((prev) =>\n\t\tprev.map((t) => (t.id === id ? { ...t, exiting: true } : t)),\n\t);\n\n\tsetTimeout(\n\t\t() => store.update((prev) => prev.filter((t) => t.id !== id)),\n\t\tEXIT_DURATION,\n\t);\n};\n\nconst resolveAutopilot = (\n\topts: InternalSileoOptions,\n\tduration: number | null,\n): { expandDelayMs?: number; collapseDelayMs?: number } => {\n\tif (opts.autopilot === false || !duration || duration <= 0) return {};\n\tconst cfg = typeof opts.autopilot === \"object\" ? opts.autopilot : undefined;\n\tconst clamp = (v: number) => Math.min(duration, Math.max(0, v));\n\treturn {\n\t\texpandDelayMs: clamp(cfg?.expand ?? AUTO_EXPAND_DELAY),\n\t\tcollapseDelayMs: clamp(cfg?.collapse ?? AUTO_COLLAPSE_DELAY),\n\t};\n};\n\nconst mergeOptions = (options: InternalSileoOptions) => ({\n\t...store.options,\n\t...options,\n\tstyles: { ...store.options?.styles, ...options.styles },\n});\n\nconst buildSileoItem = (\n\tmerged: InternalSileoOptions,\n\tid: string,\n\tfallbackPosition?: SileoPosition,\n): SileoItem => {\n\tconst duration = merged.duration ?? DEFAULT_DURATION;\n\tconst auto = resolveAutopilot(merged, duration);\n\treturn {\n\t\t...merged,\n\t\tid,\n\t\tinstanceId: generateId(),\n\t\tposition: merged.position ?? fallbackPosition ?? store.position,\n\t\tautoExpandDelayMs: auto.expandDelayMs,\n\t\tautoCollapseDelayMs: auto.collapseDelayMs,\n\t};\n};\n\nconst createToast = (options: InternalSileoOptions) => {\n\tconst live = store.toasts.filter((t) => !t.exiting);\n\tconst merged = mergeOptions(options);\n\n\tconst id = merged.id ?? \"sileo-default\";\n\tconst prev = live.find((t) => t.id === id);\n\tconst item = buildSileoItem(merged, id, prev?.position);\n\n\tif (prev) {\n\t\tstore.update((p) => p.map((t) => (t.id === id ? item : t)));\n\t} else {\n\t\tstore.update((p) => [...p.filter((t) => t.id !== id), item]);\n\t}\n\treturn { id, duration: merged.duration ?? DEFAULT_DURATION };\n};\n\nconst updateToast = (id: string, options: InternalSileoOptions) => {\n\tconst existing = store.toasts.find((t) => t.id === id);\n\tif (!existing) return;\n\n\tconst item = buildSileoItem(mergeOptions(options), id, existing.position);\n\tstore.update((prev) => prev.map((t) => (t.id === id ? item : t)));\n};\n\nexport interface SileoPromiseOptions<T = unknown> {\n\tloading: Pick<SileoOptions, \"title\" | \"icon\">;\n\tsuccess: SileoOptions | ((data: T) => SileoOptions);\n\terror: SileoOptions | ((err: unknown) => SileoOptions);\n\taction?: SileoOptions | ((data: T) => SileoOptions);\n\tposition?: SileoPosition;\n}\n\nexport const sileo = {\n\tshow: (opts: SileoOptions) => createToast(opts).id,\n\tsuccess: (opts: SileoOptions) =>\n\t\tcreateToast({ ...opts, state: \"success\" }).id,\n\terror: (opts: SileoOptions) => createToast({ ...opts, state: \"error\" }).id,\n\twarning: (opts: SileoOptions) =>\n\t\tcreateToast({ ...opts, state: \"warning\" }).id,\n\tinfo: (opts: SileoOptions) => createToast({ ...opts, state: \"info\" }).id,\n\taction: (opts: SileoOptions) => createToast({ ...opts, state: \"action\" }).id,\n\n\tpromise: <T,>(\n\t\tpromise: Promise<T> | (() => Promise<T>),\n\t\topts: SileoPromiseOptions<T>,\n\t): Promise<T> => {\n\t\tconst { id } = createToast({\n\t\t\t...opts.loading,\n\t\t\tstate: \"loading\",\n\t\t\tduration: null,\n\t\t\tposition: opts.position,\n\t\t});\n\n\t\tconst p = typeof promise === \"function\" ? promise() : promise;\n\n\t\tp.then((data) => {\n\t\t\tif (opts.action) {\n\t\t\t\tconst actionOpts =\n\t\t\t\t\ttypeof opts.action === \"function\" ? opts.action(data) : opts.action;\n\t\t\t\tupdateToast(id, { ...actionOpts, state: \"action\", id });\n\t\t\t} else {\n\t\t\t\tconst successOpts =\n\t\t\t\t\ttypeof opts.success === \"function\"\n\t\t\t\t\t\t? opts.success(data)\n\t\t\t\t\t\t: opts.success;\n\t\t\t\tupdateToast(id, { ...successOpts, state: \"success\", id });\n\t\t\t}\n\t\t}).catch((err) => {\n\t\t\tconst errorOpts =\n\t\t\t\ttypeof opts.error === \"function\" ? opts.error(err) : opts.error;\n\t\t\tupdateToast(id, { ...errorOpts, state: \"error\", id });\n\t\t});\n\n\t\treturn p;\n\t},\n\n\tdismiss: dismissToast,\n\n\tclear: (position?: SileoPosition) =>\n\t\tstore.update((prev) =>\n\t\t\tposition ? prev.filter((t) => t.position !== position) : [],\n\t\t),\n};\n\n/* ------------------------------ Toaster Component ------------------------- */\n\nexport function Toaster({\n\tchildren,\n\tposition = \"top-right\",\n\toffset,\n\toptions,\n}: SileoToasterProps) {\n\tconst [toasts, setToasts] = useState<SileoItem[]>(store.toasts);\n\tconst [activeId, setActiveId] = useState<string>();\n\n\tconst hoverRef = useRef(false);\n\tconst timersRef = useRef(new Map<string, number>());\n\tconst listRef = useRef(toasts);\n\tconst latestRef = useRef<string | undefined>(undefined);\n\tconst handlersCache = useRef(\n\t\tnew Map<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\tenter: MouseEventHandler<HTMLButtonElement>;\n\t\t\t\tleave: MouseEventHandler<HTMLButtonElement>;\n\t\t\t\tdismiss: () => void;\n\t\t\t}\n\t\t>(),\n\t);\n\n\tuseEffect(() => {\n\t\tstore.position = position;\n\t\tstore.options = options;\n\t}, [position, options]);\n\n\tconst clearAllTimers = useCallback(() => {\n\t\tfor (const t of timersRef.current.values()) clearTimeout(t);\n\t\ttimersRef.current.clear();\n\t}, []);\n\n\tconst schedule = useCallback((items: SileoItem[]) => {\n\t\tif (hoverRef.current) return;\n\n\t\tfor (const item of items) {\n\t\t\tif (item.exiting) continue;\n\t\t\tconst key = timeoutKey(item);\n\t\t\tif (timersRef.current.has(key)) continue;\n\n\t\t\tconst dur = item.duration ?? DEFAULT_DURATION;\n\t\t\tif (dur === null || dur <= 0) continue;\n\n\t\t\ttimersRef.current.set(\n\t\t\t\tkey,\n\t\t\t\twindow.setTimeout(() => dismissToast(item.id), dur),\n\t\t\t);\n\t\t}\n\t}, []);\n\n\tuseEffect(() => {\n\t\tconst listener: SileoListener = (next) => setToasts(next);\n\t\tstore.listeners.add(listener);\n\t\treturn () => {\n\t\t\tstore.listeners.delete(listener);\n\t\t\tclearAllTimers();\n\t\t};\n\t}, [clearAllTimers]);\n\n\tuseEffect(() => {\n\t\tlistRef.current = toasts;\n\n\t\tconst toastKeys = new Set(toasts.map(timeoutKey));\n\t\tconst toastIds = new Set(toasts.map((t) => t.id));\n\t\tfor (const [key, timer] of timersRef.current) {\n\t\t\tif (!toastKeys.has(key)) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\ttimersRef.current.delete(key);\n\t\t\t}\n\t\t}\n\t\tfor (const id of handlersCache.current.keys()) {\n\t\t\tif (!toastIds.has(id)) handlersCache.current.delete(id);\n\t\t}\n\n\t\tschedule(toasts);\n\t}, [toasts, schedule]);\n\n\tconst handleMouseEnterRef =\n\t\tuseRef<MouseEventHandler<HTMLButtonElement>>(null);\n\tconst handleMouseLeaveRef =\n\t\tuseRef<MouseEventHandler<HTMLButtonElement>>(null);\n\n\thandleMouseEnterRef.current = useCallback<\n\t\tMouseEventHandler<HTMLButtonElement>\n\t>(() => {\n\t\tif (hoverRef.current) return;\n\t\thoverRef.current = true;\n\t\tclearAllTimers();\n\t}, [clearAllTimers]);\n\n\thandleMouseLeaveRef.current = useCallback<\n\t\tMouseEventHandler<HTMLButtonElement>\n\t>(() => {\n\t\tif (!hoverRef.current) return;\n\t\thoverRef.current = false;\n\t\tschedule(listRef.current);\n\t}, [schedule]);\n\n\tconst latest = useMemo(() => {\n\t\tfor (let i = toasts.length - 1; i >= 0; i--) {\n\t\t\tif (!toasts[i].exiting) return toasts[i].id;\n\t\t}\n\t\treturn undefined;\n\t}, [toasts]);\n\n\tuseEffect(() => {\n\t\tlatestRef.current = latest;\n\t\tsetActiveId(latest);\n\t}, [latest]);\n\n\tconst getHandlers = useCallback((toastId: string) => {\n\t\tlet cached = handlersCache.current.get(toastId);\n\t\tif (cached) return cached;\n\n\t\tcached = {\n\t\t\tenter: ((e) => {\n\t\t\t\tsetActiveId((prev) => (prev === toastId ? prev : toastId));\n\t\t\t\thandleMouseEnterRef.current?.(e);\n\t\t\t}) as MouseEventHandler<HTMLButtonElement>,\n\t\t\tleave: ((e) => {\n\t\t\t\tsetActiveId((prev) =>\n\t\t\t\t\tprev === latestRef.current ? prev : latestRef.current,\n\t\t\t\t);\n\t\t\t\thandleMouseLeaveRef.current?.(e);\n\t\t\t}) as MouseEventHandler<HTMLButtonElement>,\n\t\t\tdismiss: () => dismissToast(toastId),\n\t\t};\n\n\t\thandlersCache.current.set(toastId, cached);\n\t\treturn cached;\n\t}, []);\n\n\tconst getViewportStyle = useCallback(\n\t\t(pos: SileoPosition): CSSProperties | undefined => {\n\t\t\tif (offset === undefined) return undefined;\n\n\t\t\tconst o =\n\t\t\t\ttypeof offset === \"object\"\n\t\t\t\t\t? offset\n\t\t\t\t\t: { top: offset, right: offset, bottom: offset, left: offset };\n\n\t\t\tconst s: CSSProperties = {};\n\t\t\tconst px = (v: SileoOffsetValue) =>\n\t\t\t\ttypeof v === \"number\" ? `${v}px` : v;\n\n\t\t\tif (pos.startsWith(\"top\") && o.top) s.top = px(o.top);\n\t\t\tif (pos.startsWith(\"bottom\") && o.bottom) s.bottom = px(o.bottom);\n\t\t\tif (pos.endsWith(\"left\") && o.left) s.left = px(o.left);\n\t\t\tif (pos.endsWith(\"right\") && o.right) s.right = px(o.right);\n\n\t\t\treturn s;\n\t\t},\n\t\t[offset],\n\t);\n\n\tconst byPosition = useMemo(() => {\n\t\tconst map = {} as Partial<Record<SileoPosition, SileoItem[]>>;\n\t\tfor (const t of toasts) {\n\t\t\tconst pos = t.position ?? position;\n\t\t\tconst arr = map[pos];\n\t\t\tif (arr) {\n\t\t\t\tarr.push(t);\n\t\t\t} else {\n\t\t\t\tmap[pos] = [t];\n\t\t\t}\n\t\t}\n\t\treturn map;\n\t}, [toasts, position]);\n\n\treturn (\n\t\t<>\n\t\t\t{children}\n\t\t\t{SILEO_POSITIONS.map((pos) => {\n\t\t\t\tconst items = byPosition[pos];\n\t\t\t\tif (!items?.length) return null;\n\n\t\t\t\tconst pill = pillAlign(pos);\n\t\t\t\tconst expand = expandDir(pos);\n\n\t\t\t\treturn (\n\t\t\t\t\t<section\n\t\t\t\t\t\tkey={pos}\n\t\t\t\t\t\tdata-sileo-viewport\n\t\t\t\t\t\tdata-position={pos}\n\t\t\t\t\t\taria-live=\"polite\"\n\t\t\t\t\t\tstyle={getViewportStyle(pos)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{items.map((item) => {\n\t\t\t\t\t\t\tconst h = getHandlers(item.id);\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<Sileo\n\t\t\t\t\t\t\t\t\tkey={item.id}\n\t\t\t\t\t\t\t\t\tid={item.id}\n\t\t\t\t\t\t\t\t\tstate={item.state}\n\t\t\t\t\t\t\t\t\ttitle={item.title}\n\t\t\t\t\t\t\t\t\tdescription={item.description}\n\t\t\t\t\t\t\t\t\tposition={pill}\n\t\t\t\t\t\t\t\t\texpand={expand}\n\t\t\t\t\t\t\t\t\ticon={item.icon}\n\t\t\t\t\t\t\t\t\tfill={item.fill}\n\t\t\t\t\t\t\t\t\tstyles={item.styles}\n\t\t\t\t\t\t\t\t\tbutton={item.button}\n\t\t\t\t\t\t\t\t\troundness={item.roundness}\n\t\t\t\t\t\t\t\t\texiting={item.exiting}\n\t\t\t\t\t\t\t\t\tautoExpandDelayMs={item.autoExpandDelayMs}\n\t\t\t\t\t\t\t\t\tautoCollapseDelayMs={item.autoCollapseDelayMs}\n\t\t\t\t\t\t\t\t\trefreshKey={item.instanceId}\n\t\t\t\t\t\t\t\t\tcanExpand={activeId === undefined || activeId === item.id}\n\t\t\t\t\t\t\t\t\tonMouseEnter={h.enter}\n\t\t\t\t\t\t\t\t\tonMouseLeave={h.leave}\n\t\t\t\t\t\t\t\t\tonDismiss={h.dismiss}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</section>\n\t\t\t\t);\n\t\t\t})}\n\t\t</>\n\t);\n}\n"],"names":[],"mappings":";;AACO,KAAA,UAAA;AACA,UAAA,WAAA;AACP;AACA;AACA;AACA;AACA;AACO,UAAA,WAAA;AACP;AACA;AACA;AACO,cAAA,eAAA;AACA,KAAA,aAAA,WAAA,eAAA;AACA,UAAA,YAAA;AACP;AACA,kBAAA,SAAA;AACA,eAAA,aAAA;AACA;AACA,WAAA,SAAA;AACA,aAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,WAAA;AACA;;AC1BA,KAAA,gBAAA;AACA,KAAA,iBAAA,GAAA,OAAA,CAAA,MAAA,sCAAA,gBAAA;AACO,UAAA,iBAAA;AACP,eAAA,SAAA;AACA,eAAA,aAAA;AACA,aAAA,gBAAA,GAAA,iBAAA;AACA,cAAA,OAAA,CAAA,YAAA;AACA;AACO,UAAA,mBAAA;AACP,aAAA,IAAA,CAAA,YAAA;AACA,aAAA,YAAA,iBAAA,YAAA;AACA,WAAA,YAAA,sBAAA,YAAA;AACA,aAAA,YAAA,iBAAA,YAAA;AACA,eAAA,aAAA;AACA;AACO,cAAA,KAAA;AACP,iBAAA,YAAA;AACA,oBAAA,YAAA;AACA,kBAAA,YAAA;AACA,oBAAA,YAAA;AACA,iBAAA,YAAA;AACA,mBAAA,YAAA;AACA,0BAAA,OAAA,aAAA,OAAA,YAAA,mBAAA,QAAA,OAAA;AACA;AACA,uBAAA,aAAA;AACA;AACO,iBAAA,OAAA,2CAAA,iBAAA;;;;"}
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var cc = require('./cc-DGff5sSY.js');
|
|
|
14
14
|
var jsxRuntime = require('react/jsx-runtime');
|
|
15
15
|
var react = require('react');
|
|
16
16
|
|
|
17
|
-
__insertCSS(":root{--sileo-spring-easing:linear(\n\t\t0,\n\t\t0.002 0.6%,\n\t\t0.007 1.2%,\n\t\t0.015 1.8%,\n\t\t0.025 2.4%,\n\t\t0.057 3.7%,\n\t\t0.104 5.2%,\n\t\t0.151 6.5%,\n\t\t0.208 7.9%,\n\t\t0.455 13.6%,\n\t\t0.566 16.3%,\n\t\t0.619 17.7%,\n\t\t0.669 19.1%,\n\t\t0.715 20.5%,\n\t\t0.755 21.8%,\n\t\t0.794 23.2%,\n\t\t0.829 24.6%,\n\t\t0.861 26%,\n\t\t0.889 27.4%,\n\t\t0.914 28.8%,\n\t\t0.937 30.3%,\n\t\t0.956 31.8%,\n\t\t0.974 33.4%,\n\t\t0.987 34.8%,\n\t\t0.997 36.2%,\n\t\t1.014 39.2%,\n\t\t1.024 42.5%,\n\t\t1.028 46.3%,\n\t\t1.026 51.9%,\n\t\t1.01 66.1%,\n\t\t1.003 74.9%,\n\t\t1 85.2%,\n\t\t1\n\t);--sileo-duration:600ms;--sileo-height:40px;--sileo-width:350px;--sileo-state-success:oklch(0.723 0.219 142.136);--sileo-state-loading:oklch(0.556 0 0);--sileo-state-error:oklch(0.637 0.237 25.331);--sileo-state-warning:oklch(0.795 0.184 86.047);--sileo-state-info:oklch(0.685 0.169 237.323);--sileo-state-action:oklch(0.623 0.214 259.815)}[data-sileo-toast]{position:relative;cursor:pointer;pointer-events:auto;border:0;background:0 0;padding:0;width:var(--sileo-width);height:var(--sileo-button-height,var(--sileo-height));opacity:0;transform:translateZ(0) scale(.95);transform-origin:center;filter:drop-shadow(0 0 8px rgba(0, 0, 0, .05));contain:layout style;overflow:visible}[data-sileo-toast][data-state=loading]{cursor:default}[data-sileo-toast][data-ready=true]{opacity:1;transform:translateZ(0) scale(1);transition:transform calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),opacity calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),margin-bottom calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),margin-top calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),height var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-viewport][data-position^=top] [data-sileo-toast]:not([data-ready=true]){transform:translateY(-6px) scale(.95)}[data-sileo-viewport][data-position^=bottom] [data-sileo-toast]:not([data-ready=true]){transform:translateY(6px) scale(.95)}[data-sileo-toast][data-ready=true][data-exiting=true]{opacity:0;pointer-events:none}[data-sileo-viewport][data-position^=top] [data-sileo-toast][data-ready=true][data-exiting=true]{transform:translateY(-6px) scale(.95)}[data-sileo-viewport][data-position^=bottom] [data-sileo-toast][data-ready=true][data-exiting=true]{transform:translateY(6px) scale(.95)}[data-sileo-canvas]{position:absolute;left:0;right:0;pointer-events:none;transform:translateZ(0);contain:layout style;overflow:visible}[data-sileo-canvas][data-edge=top]{bottom:0;transform:scaleY(-1) translateZ(0)}[data-sileo-canvas][data-edge=bottom]{top:0}[data-sileo-svg]{overflow:visible}[data-sileo-body],[data-sileo-pill]{transform-box:fill-box;transform-origin:50% 0%}[data-sileo-toast][data-ready=true] [data-sileo-pill]{transition:transform var(--sileo-duration) var(--sileo-spring-easing),width var(--sileo-duration) var(--sileo-spring-easing),height var(--sileo-duration) var(--sileo-spring-easing),x var(--sileo-duration) var(--sileo-spring-easing),fill var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-toast][data-ready=true][data-expanded=true] [data-sileo-pill]{transition-delay:calc(var(--sileo-duration) * 0.08)}[data-sileo-toast][data-ready=true] [data-sileo-body]{transition:transform var(--sileo-duration) var(--sileo-spring-easing),opacity var(--sileo-duration) var(--sileo-spring-easing),fill var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-header]{position:absolute;z-index:20;display:flex;align-items:center;padding:.5rem;height:var(--sileo-height);overflow:hidden}[data-sileo-toast][data-ready=true] [data-sileo-header]{max-width:var(--sileo-pill-width);transition:transform var(--sileo-duration) var(--sileo-spring-easing),left var(--sileo-duration) var(--sileo-spring-easing),max-width var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-header][data-edge=top]{bottom:0}[data-sileo-header][data-edge=bottom]{top:0}[data-sileo-header-stack]{position:relative;display:inline-flex;align-items:center;height:100%}[data-sileo-header-inner]{display:flex;align-items:center;gap:.5rem;white-space:nowrap;opacity:1;filter:blur(0px)}[data-sileo-header-inner][data-layer=current]{animation:sileo-header-enter 1s var(--sileo-spring-easing) both}[data-sileo-header-inner][data-layer=prev]{position:absolute;left:0;top:0;pointer-events:none}[data-sileo-header-inner][data-exiting=true]{animation:sileo-header-exit 150ms ease forwards}[data-sileo-badge]{display:flex;height:24px;width:24px;flex-shrink:0;align-items:center;justify-content:center;padding:2px;box-sizing:border-box;border-radius:9999px;color:var(--sileo-tone,currentColor);background-color:var(--sileo-tone-bg,transparent)}[data-sileo-title]{font-size:.825rem;line-height:1rem;font-weight:500;text-transform:capitalize;color:var(--sileo-tone,currentColor)}:is([data-sileo-badge],[data-sileo-title])[data-state]{--_c:var(--sileo-state-success);--sileo-tone:var(--_c);--sileo-tone-bg:color-mix(in oklch, var(--_c) 20%, transparent)}:is([data-sileo-badge],[data-sileo-title])[data-state=loading]{--_c:var(--sileo-state-loading)}:is([data-sileo-badge],[data-sileo-title])[data-state=error]{--_c:var(--sileo-state-error)}:is([data-sileo-badge],[data-sileo-title])[data-state=warning]{--_c:var(--sileo-state-warning)}:is([data-sileo-badge],[data-sileo-title])[data-state=info]{--_c:var(--sileo-state-info)}:is([data-sileo-badge],[data-sileo-title])[data-state=action]{--_c:var(--sileo-state-action)}[data-sileo-content]{position:absolute;left:0;z-index:10;width:100%;pointer-events:none}[data-sileo-toast][data-ready=true] [data-sileo-content]{transition:opacity calc(var(--sileo-duration) * .08) var(--sileo-spring-easing) calc(var(--sileo-duration) * .04)}[data-sileo-content][data-edge=top]{top:0}[data-sileo-content][data-edge=bottom]{top:var(--sileo-height)}[data-sileo-content][data-visible=true]{pointer-events:auto}[data-sileo-toast][data-ready=true] [data-sileo-content][data-visible=true]{transition:opacity var(--sileo-duration) var(--sileo-spring-easing) calc(var(--sileo-duration) * .25)}[data-sileo-description]{width:100%;text-align:left;padding:1rem;font-size:.875rem;line-height:1.25rem;contain:layout style;content-visibility:auto}[data-sileo-button]{display:flex;align-items:center;justify-content:center;height:1.75rem;padding:0 .625rem;margin-top:.75rem;border-radius:9999px;border:0;font-size:.75rem;font-weight:500;cursor:pointer;color:var(--sileo-btn-color,currentColor);background-color:var(--sileo-btn-bg,transparent);transition:background-color 150ms ease}[data-sileo-button]:hover{background-color:var(--sileo-btn-bg-hover,transparent)}[data-sileo-button][data-state]{--_c:var(--sileo-state-success);--sileo-btn-color:var(--_c);--sileo-btn-bg:color-mix(in oklch, var(--_c) 15%, transparent);--sileo-btn-bg-hover:color-mix(in oklch, var(--_c) 25%, transparent)}[data-sileo-button][data-state=loading]{--_c:var(--sileo-state-loading)}[data-sileo-button][data-state=error]{--_c:var(--sileo-state-error)}[data-sileo-button][data-state=warning]{--_c:var(--sileo-state-warning)}[data-sileo-button][data-state=info]{--_c:var(--sileo-state-info)}[data-sileo-button][data-state=action]{--_c:var(--sileo-state-action)}[data-sileo-icon=spin]{animation:sileo-spin 1s linear infinite}@keyframes sileo-spin{to{rotate:360deg}}@keyframes sileo-header-enter{from{opacity:0;filter:blur(6px)}to{opacity:1;filter:blur(0px)}}@keyframes sileo-header-exit{from{opacity:1;filter:blur(0px)}to{opacity:0;filter:blur(6px)}}[data-sileo-viewport]{position:fixed;z-index:50;display:flex;gap:.75rem;padding:.75rem;pointer-events:none;max-width:calc(100vw - 1.5rem);contain:layout style}[data-sileo-viewport][data-position^=top] [data-sileo-toast]:not([data-ready=true]){margin-bottom:calc(-1 * (var(--sileo-height) + .75rem))}[data-sileo-viewport][data-position^=bottom] [data-sileo-toast]:not([data-ready=true]){margin-top:calc(-1 * (var(--sileo-height) + .75rem))}[data-sileo-viewport][data-position^=top]{top:0;flex-direction:column-reverse}[data-sileo-viewport][data-position^=bottom]{bottom:0;flex-direction:column}[data-sileo-viewport][data-position$=left]{left:0;align-items:flex-start}[data-sileo-viewport][data-position$=right]{right:0;align-items:flex-end}[data-sileo-viewport][data-position$=center]{left:50%;transform:translateX(-50%);align-items:center}@media (prefers-reduced-motion:no-preference){[data-sileo-toast][data-ready=true]{will-change:transform,opacity}[data-sileo-toast][data-ready=true][data-expanded=true]{will-change:transform,opacity,height}[data-sileo-body],[data-sileo-pill]{will-change:transform}[data-sileo-canvas]{will-change:filter}}@media (prefers-reduced-motion:reduce){*,::after,::before{animation-duration:0s;animation-iteration-count:1;transition-duration:0s}}");
|
|
17
|
+
__insertCSS(":root{--sileo-spring-easing:linear(\n\t\t0,\n\t\t0.002 0.6%,\n\t\t0.007 1.2%,\n\t\t0.015 1.8%,\n\t\t0.025 2.4%,\n\t\t0.057 3.7%,\n\t\t0.104 5.2%,\n\t\t0.151 6.5%,\n\t\t0.208 7.9%,\n\t\t0.455 13.6%,\n\t\t0.566 16.3%,\n\t\t0.619 17.7%,\n\t\t0.669 19.1%,\n\t\t0.715 20.5%,\n\t\t0.755 21.8%,\n\t\t0.794 23.2%,\n\t\t0.829 24.6%,\n\t\t0.861 26%,\n\t\t0.889 27.4%,\n\t\t0.914 28.8%,\n\t\t0.937 30.3%,\n\t\t0.956 31.8%,\n\t\t0.974 33.4%,\n\t\t0.987 34.8%,\n\t\t0.997 36.2%,\n\t\t1.014 39.2%,\n\t\t1.024 42.5%,\n\t\t1.028 46.3%,\n\t\t1.026 51.9%,\n\t\t1.01 66.1%,\n\t\t1.003 74.9%,\n\t\t1 85.2%,\n\t\t1\n\t);--sileo-duration:600ms;--sileo-height:40px;--sileo-width:350px;--sileo-state-success:oklch(0.723 0.219 142.136);--sileo-state-loading:oklch(0.556 0 0);--sileo-state-error:oklch(0.637 0.237 25.331);--sileo-state-warning:oklch(0.795 0.184 86.047);--sileo-state-info:oklch(0.685 0.169 237.323);--sileo-state-action:oklch(0.623 0.214 259.815)}[data-sileo-toast]{position:relative;cursor:pointer;pointer-events:auto;touch-action:none;border:0;background:0 0;padding:0;width:var(--sileo-width);height:var(--sileo-button-height,var(--sileo-height));opacity:0;transform:translateZ(0) scale(.95);transform-origin:center;filter:drop-shadow(0 0 8px rgba(0, 0, 0, .05));contain:layout style;overflow:visible}[data-sileo-toast][data-state=loading]{cursor:default}[data-sileo-toast][data-ready=true]{opacity:1;transform:translateZ(0) scale(1);transition:transform calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),opacity calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),margin-bottom calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),margin-top calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),height var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-viewport][data-position^=top] [data-sileo-toast]:not([data-ready=true]){transform:translateY(-6px) scale(.95)}[data-sileo-viewport][data-position^=bottom] [data-sileo-toast]:not([data-ready=true]){transform:translateY(6px) scale(.95)}[data-sileo-toast][data-ready=true][data-exiting=true]{opacity:0;pointer-events:none}[data-sileo-viewport][data-position^=top] [data-sileo-toast][data-ready=true][data-exiting=true]{transform:translateY(-6px) scale(.95)}[data-sileo-viewport][data-position^=bottom] [data-sileo-toast][data-ready=true][data-exiting=true]{transform:translateY(6px) scale(.95)}[data-sileo-canvas]{position:absolute;left:0;right:0;pointer-events:none;transform:translateZ(0);contain:layout style;overflow:visible}[data-sileo-canvas][data-edge=top]{bottom:0;transform:scaleY(-1) translateZ(0)}[data-sileo-canvas][data-edge=bottom]{top:0}[data-sileo-svg]{overflow:visible}[data-sileo-body],[data-sileo-pill]{transform-box:fill-box;transform-origin:50% 0%}[data-sileo-toast][data-ready=true] [data-sileo-pill]{transition:transform var(--sileo-duration) var(--sileo-spring-easing),width var(--sileo-duration) var(--sileo-spring-easing),height var(--sileo-duration) var(--sileo-spring-easing),x var(--sileo-duration) var(--sileo-spring-easing),fill var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-toast][data-ready=true][data-expanded=true] [data-sileo-pill]{transition-delay:calc(var(--sileo-duration) * 0.08)}[data-sileo-toast][data-ready=true] [data-sileo-body]{transition:transform var(--sileo-duration) var(--sileo-spring-easing),opacity var(--sileo-duration) var(--sileo-spring-easing),fill var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-header]{position:absolute;z-index:20;display:flex;align-items:center;padding:.5rem;height:var(--sileo-height);overflow:hidden}[data-sileo-toast][data-ready=true] [data-sileo-header]{max-width:var(--sileo-pill-width);transition:transform var(--sileo-duration) var(--sileo-spring-easing),left var(--sileo-duration) var(--sileo-spring-easing),max-width var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-header][data-edge=top]{bottom:0}[data-sileo-header][data-edge=bottom]{top:0}[data-sileo-header-stack]{position:relative;display:inline-flex;align-items:center;height:100%}[data-sileo-header-inner]{display:flex;align-items:center;gap:.5rem;white-space:nowrap;opacity:1;filter:blur(0px)}[data-sileo-header-inner][data-layer=current]{animation:sileo-header-enter 1s var(--sileo-spring-easing) both}[data-sileo-header-inner][data-layer=prev]{position:absolute;left:0;top:0;pointer-events:none}[data-sileo-header-inner][data-exiting=true]{animation:sileo-header-exit 150ms ease forwards}[data-sileo-badge]{display:flex;height:24px;width:24px;flex-shrink:0;align-items:center;justify-content:center;padding:2px;box-sizing:border-box;border-radius:9999px;color:var(--sileo-tone,currentColor);background-color:var(--sileo-tone-bg,transparent)}[data-sileo-title]{font-size:.825rem;line-height:1rem;font-weight:500;text-transform:capitalize;color:var(--sileo-tone,currentColor)}:is([data-sileo-badge],[data-sileo-title])[data-state]{--_c:var(--sileo-state-success);--sileo-tone:var(--_c);--sileo-tone-bg:color-mix(in oklch, var(--_c) 20%, transparent)}:is([data-sileo-badge],[data-sileo-title])[data-state=loading]{--_c:var(--sileo-state-loading)}:is([data-sileo-badge],[data-sileo-title])[data-state=error]{--_c:var(--sileo-state-error)}:is([data-sileo-badge],[data-sileo-title])[data-state=warning]{--_c:var(--sileo-state-warning)}:is([data-sileo-badge],[data-sileo-title])[data-state=info]{--_c:var(--sileo-state-info)}:is([data-sileo-badge],[data-sileo-title])[data-state=action]{--_c:var(--sileo-state-action)}[data-sileo-content]{position:absolute;left:0;z-index:10;width:100%;pointer-events:none}[data-sileo-toast][data-ready=true] [data-sileo-content]{transition:opacity calc(var(--sileo-duration) * .08) var(--sileo-spring-easing) calc(var(--sileo-duration) * .04)}[data-sileo-content][data-edge=top]{top:0}[data-sileo-content][data-edge=bottom]{top:var(--sileo-height)}[data-sileo-content][data-visible=true]{pointer-events:auto}[data-sileo-toast][data-ready=true] [data-sileo-content][data-visible=true]{transition:opacity var(--sileo-duration) var(--sileo-spring-easing) calc(var(--sileo-duration) * .25)}[data-sileo-description]{width:100%;text-align:left;padding:1rem;font-size:.875rem;line-height:1.25rem;contain:layout style;content-visibility:auto}[data-sileo-button]{display:flex;align-items:center;justify-content:center;height:1.75rem;padding:0 .625rem;margin-top:.75rem;border-radius:9999px;border:0;font-size:.75rem;font-weight:500;cursor:pointer;color:var(--sileo-btn-color,currentColor);background-color:var(--sileo-btn-bg,transparent);transition:background-color 150ms ease}[data-sileo-button]:hover{background-color:var(--sileo-btn-bg-hover,transparent)}[data-sileo-button][data-state]{--_c:var(--sileo-state-success);--sileo-btn-color:var(--_c);--sileo-btn-bg:color-mix(in oklch, var(--_c) 15%, transparent);--sileo-btn-bg-hover:color-mix(in oklch, var(--_c) 25%, transparent)}[data-sileo-button][data-state=loading]{--_c:var(--sileo-state-loading)}[data-sileo-button][data-state=error]{--_c:var(--sileo-state-error)}[data-sileo-button][data-state=warning]{--_c:var(--sileo-state-warning)}[data-sileo-button][data-state=info]{--_c:var(--sileo-state-info)}[data-sileo-button][data-state=action]{--_c:var(--sileo-state-action)}[data-sileo-icon=spin]{animation:sileo-spin 1s linear infinite}@keyframes sileo-spin{to{rotate:360deg}}@keyframes sileo-header-enter{from{opacity:0;filter:blur(6px)}to{opacity:1;filter:blur(0px)}}@keyframes sileo-header-exit{from{opacity:1;filter:blur(0px)}to{opacity:0;filter:blur(6px)}}[data-sileo-viewport]{position:fixed;z-index:50;display:flex;gap:.75rem;padding:.75rem;pointer-events:none;max-width:calc(100vw - 1.5rem);contain:layout style}[data-sileo-viewport][data-position^=top] [data-sileo-toast]:not([data-ready=true]){margin-bottom:calc(-1 * (var(--sileo-height) + .75rem))}[data-sileo-viewport][data-position^=bottom] [data-sileo-toast]:not([data-ready=true]){margin-top:calc(-1 * (var(--sileo-height) + .75rem))}[data-sileo-viewport][data-position^=top]{top:0;flex-direction:column-reverse}[data-sileo-viewport][data-position^=bottom]{bottom:0;flex-direction:column}[data-sileo-viewport][data-position$=left]{left:0;align-items:flex-start}[data-sileo-viewport][data-position$=right]{right:0;align-items:flex-end}[data-sileo-viewport][data-position$=center]{left:50%;transform:translateX(-50%);align-items:center}@media (prefers-reduced-motion:no-preference){[data-sileo-toast][data-ready=true]{will-change:transform,opacity}[data-sileo-toast][data-ready=true][data-expanded=true]{will-change:transform,opacity,height}[data-sileo-body],[data-sileo-pill]{will-change:transform}[data-sileo-canvas]{will-change:filter}}@media (prefers-reduced-motion:reduce){*,::after,::before{animation-duration:0s;animation-iteration-count:1;transition-duration:0s}}");
|
|
18
18
|
|
|
19
19
|
const ArrowRight = ()=>/*#__PURE__*/ jsxRuntime.jsxs("svg", {
|
|
20
20
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -219,7 +219,7 @@ const HEADER_EXIT_MS = 150;
|
|
|
219
219
|
})
|
|
220
220
|
});
|
|
221
221
|
});
|
|
222
|
-
/* ------------------------------- Component -------------------------------- */ const Sileo = /*#__PURE__*/ react.memo(function Sileo({ id, fill = "#FFFFFF", state = "success", title = state, description, position = "left", expand = "bottom", className, icon, styles, button, roundness, exiting = false, autoExpandDelayMs, autoCollapseDelayMs, canExpand, interruptKey, refreshKey, onMouseEnter, onMouseLeave }) {
|
|
222
|
+
/* ------------------------------- Component -------------------------------- */ const Sileo = /*#__PURE__*/ react.memo(function Sileo({ id, fill = "#FFFFFF", state = "success", title = state, description, position = "left", expand = "bottom", className, icon, styles, button, roundness, exiting = false, autoExpandDelayMs, autoCollapseDelayMs, canExpand, interruptKey, refreshKey, onMouseEnter, onMouseLeave, onDismiss }) {
|
|
223
223
|
var _headerLayer_current_view_icon, _headerLayer_prev_view_icon;
|
|
224
224
|
var _headerLayer_current_view_styles, _headerLayer_current_view_styles1, _headerLayer_prev_view_styles, _headerLayer_prev_view_styles1, _view_styles, _view_styles1;
|
|
225
225
|
const next = react.useMemo(()=>({
|
|
@@ -503,7 +503,48 @@ const HEADER_EXIT_MS = 150;
|
|
|
503
503
|
}, [
|
|
504
504
|
open
|
|
505
505
|
]);
|
|
506
|
+
/* -------------------------------- Swipe ----------------------------------- */ const SWIPE_DISMISS = 30;
|
|
507
|
+
const SWIPE_MAX = 20;
|
|
508
|
+
const buttonRef = react.useRef(null);
|
|
509
|
+
const pointerStartRef = react.useRef(null);
|
|
510
|
+
const onDismissRef = react.useRef(onDismiss);
|
|
511
|
+
onDismissRef.current = onDismiss;
|
|
512
|
+
react.useEffect(()=>{
|
|
513
|
+
const el = buttonRef.current;
|
|
514
|
+
if (!el) return;
|
|
515
|
+
const onMove = (e)=>{
|
|
516
|
+
if (pointerStartRef.current === null) return;
|
|
517
|
+
const dy = e.clientY - pointerStartRef.current;
|
|
518
|
+
const sign = dy > 0 ? 1 : -1;
|
|
519
|
+
const clamped = Math.min(Math.abs(dy), SWIPE_MAX) * sign;
|
|
520
|
+
el.style.transform = `translateY(${clamped}px)`;
|
|
521
|
+
};
|
|
522
|
+
const onUp = (e)=>{
|
|
523
|
+
if (pointerStartRef.current === null) return;
|
|
524
|
+
const dy = e.clientY - pointerStartRef.current;
|
|
525
|
+
pointerStartRef.current = null;
|
|
526
|
+
el.style.transform = "";
|
|
527
|
+
if (Math.abs(dy) > SWIPE_DISMISS) {
|
|
528
|
+
onDismissRef.current == null ? void 0 : onDismissRef.current.call(onDismissRef);
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
el.addEventListener("pointermove", onMove);
|
|
532
|
+
el.addEventListener("pointerup", onUp);
|
|
533
|
+
return ()=>{
|
|
534
|
+
el.removeEventListener("pointermove", onMove);
|
|
535
|
+
el.removeEventListener("pointerup", onUp);
|
|
536
|
+
};
|
|
537
|
+
}, []);
|
|
538
|
+
const handlePointerDown = react.useCallback((e)=>{
|
|
539
|
+
if (exiting || !onDismiss) return;
|
|
540
|
+
pointerStartRef.current = e.clientY;
|
|
541
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
542
|
+
}, [
|
|
543
|
+
exiting,
|
|
544
|
+
onDismiss
|
|
545
|
+
]);
|
|
506
546
|
/* --------------------------------- Render --------------------------------- */ return /*#__PURE__*/ jsxRuntime.jsxs("button", {
|
|
547
|
+
ref: buttonRef,
|
|
507
548
|
type: "button",
|
|
508
549
|
"data-sileo-toast": true,
|
|
509
550
|
"data-ready": ready,
|
|
@@ -517,6 +558,7 @@ const HEADER_EXIT_MS = 150;
|
|
|
517
558
|
onMouseEnter: handleEnter,
|
|
518
559
|
onMouseLeave: handleLeave,
|
|
519
560
|
onTransitionEnd: handleTransitionEnd,
|
|
561
|
+
onPointerDown: handlePointerDown,
|
|
520
562
|
children: [
|
|
521
563
|
/*#__PURE__*/ jsxRuntime.jsx("div", {
|
|
522
564
|
"data-sileo-canvas": true,
|
|
@@ -719,7 +761,7 @@ const createToast = (options)=>{
|
|
|
719
761
|
store.update((p)=>p.map((t)=>t.id === id ? item : t));
|
|
720
762
|
} else {
|
|
721
763
|
store.update((p)=>[
|
|
722
|
-
...p,
|
|
764
|
+
...p.filter((t)=>t.id !== id),
|
|
723
765
|
item
|
|
724
766
|
]);
|
|
725
767
|
}
|
|
@@ -754,7 +796,8 @@ const sileo = {
|
|
|
754
796
|
promise: (promise, opts)=>{
|
|
755
797
|
const { id } = createToast(cc._extends({}, opts.loading, {
|
|
756
798
|
state: "loading",
|
|
757
|
-
duration: null
|
|
799
|
+
duration: null,
|
|
800
|
+
position: opts.position
|
|
758
801
|
}));
|
|
759
802
|
const p = typeof promise === "function" ? promise() : promise;
|
|
760
803
|
p.then((data)=>{
|
|
@@ -883,7 +926,8 @@ const sileo = {
|
|
|
883
926
|
leave: (e)=>{
|
|
884
927
|
setActiveId((prev)=>prev === latestRef.current ? prev : latestRef.current);
|
|
885
928
|
handleMouseLeaveRef.current == null ? void 0 : handleMouseLeaveRef.current.call(handleMouseLeaveRef, e);
|
|
886
|
-
}
|
|
929
|
+
},
|
|
930
|
+
dismiss: ()=>dismissToast(toastId)
|
|
887
931
|
};
|
|
888
932
|
handlersCache.current.set(toastId, cached);
|
|
889
933
|
return cached;
|
|
@@ -958,7 +1002,8 @@ const sileo = {
|
|
|
958
1002
|
refreshKey: item.instanceId,
|
|
959
1003
|
canExpand: activeId === undefined || activeId === item.id,
|
|
960
1004
|
onMouseEnter: h.enter,
|
|
961
|
-
onMouseLeave: h.leave
|
|
1005
|
+
onMouseLeave: h.leave,
|
|
1006
|
+
onDismiss: h.dismiss
|
|
962
1007
|
}, item.id);
|
|
963
1008
|
})
|
|
964
1009
|
}, pos);
|
package/dist/index.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import { _ as _extends } from './cc-2Yt7NqMX.mjs';
|
|
|
12
12
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
13
13
|
import { memo, useMemo, useState, useRef, useLayoutEffect, useEffect, useCallback } from 'react';
|
|
14
14
|
|
|
15
|
-
__insertCSS(":root{--sileo-spring-easing:linear(\n\t\t0,\n\t\t0.002 0.6%,\n\t\t0.007 1.2%,\n\t\t0.015 1.8%,\n\t\t0.025 2.4%,\n\t\t0.057 3.7%,\n\t\t0.104 5.2%,\n\t\t0.151 6.5%,\n\t\t0.208 7.9%,\n\t\t0.455 13.6%,\n\t\t0.566 16.3%,\n\t\t0.619 17.7%,\n\t\t0.669 19.1%,\n\t\t0.715 20.5%,\n\t\t0.755 21.8%,\n\t\t0.794 23.2%,\n\t\t0.829 24.6%,\n\t\t0.861 26%,\n\t\t0.889 27.4%,\n\t\t0.914 28.8%,\n\t\t0.937 30.3%,\n\t\t0.956 31.8%,\n\t\t0.974 33.4%,\n\t\t0.987 34.8%,\n\t\t0.997 36.2%,\n\t\t1.014 39.2%,\n\t\t1.024 42.5%,\n\t\t1.028 46.3%,\n\t\t1.026 51.9%,\n\t\t1.01 66.1%,\n\t\t1.003 74.9%,\n\t\t1 85.2%,\n\t\t1\n\t);--sileo-duration:600ms;--sileo-height:40px;--sileo-width:350px;--sileo-state-success:oklch(0.723 0.219 142.136);--sileo-state-loading:oklch(0.556 0 0);--sileo-state-error:oklch(0.637 0.237 25.331);--sileo-state-warning:oklch(0.795 0.184 86.047);--sileo-state-info:oklch(0.685 0.169 237.323);--sileo-state-action:oklch(0.623 0.214 259.815)}[data-sileo-toast]{position:relative;cursor:pointer;pointer-events:auto;border:0;background:0 0;padding:0;width:var(--sileo-width);height:var(--sileo-button-height,var(--sileo-height));opacity:0;transform:translateZ(0) scale(.95);transform-origin:center;filter:drop-shadow(0 0 8px rgba(0, 0, 0, .05));contain:layout style;overflow:visible}[data-sileo-toast][data-state=loading]{cursor:default}[data-sileo-toast][data-ready=true]{opacity:1;transform:translateZ(0) scale(1);transition:transform calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),opacity calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),margin-bottom calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),margin-top calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),height var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-viewport][data-position^=top] [data-sileo-toast]:not([data-ready=true]){transform:translateY(-6px) scale(.95)}[data-sileo-viewport][data-position^=bottom] [data-sileo-toast]:not([data-ready=true]){transform:translateY(6px) scale(.95)}[data-sileo-toast][data-ready=true][data-exiting=true]{opacity:0;pointer-events:none}[data-sileo-viewport][data-position^=top] [data-sileo-toast][data-ready=true][data-exiting=true]{transform:translateY(-6px) scale(.95)}[data-sileo-viewport][data-position^=bottom] [data-sileo-toast][data-ready=true][data-exiting=true]{transform:translateY(6px) scale(.95)}[data-sileo-canvas]{position:absolute;left:0;right:0;pointer-events:none;transform:translateZ(0);contain:layout style;overflow:visible}[data-sileo-canvas][data-edge=top]{bottom:0;transform:scaleY(-1) translateZ(0)}[data-sileo-canvas][data-edge=bottom]{top:0}[data-sileo-svg]{overflow:visible}[data-sileo-body],[data-sileo-pill]{transform-box:fill-box;transform-origin:50% 0%}[data-sileo-toast][data-ready=true] [data-sileo-pill]{transition:transform var(--sileo-duration) var(--sileo-spring-easing),width var(--sileo-duration) var(--sileo-spring-easing),height var(--sileo-duration) var(--sileo-spring-easing),x var(--sileo-duration) var(--sileo-spring-easing),fill var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-toast][data-ready=true][data-expanded=true] [data-sileo-pill]{transition-delay:calc(var(--sileo-duration) * 0.08)}[data-sileo-toast][data-ready=true] [data-sileo-body]{transition:transform var(--sileo-duration) var(--sileo-spring-easing),opacity var(--sileo-duration) var(--sileo-spring-easing),fill var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-header]{position:absolute;z-index:20;display:flex;align-items:center;padding:.5rem;height:var(--sileo-height);overflow:hidden}[data-sileo-toast][data-ready=true] [data-sileo-header]{max-width:var(--sileo-pill-width);transition:transform var(--sileo-duration) var(--sileo-spring-easing),left var(--sileo-duration) var(--sileo-spring-easing),max-width var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-header][data-edge=top]{bottom:0}[data-sileo-header][data-edge=bottom]{top:0}[data-sileo-header-stack]{position:relative;display:inline-flex;align-items:center;height:100%}[data-sileo-header-inner]{display:flex;align-items:center;gap:.5rem;white-space:nowrap;opacity:1;filter:blur(0px)}[data-sileo-header-inner][data-layer=current]{animation:sileo-header-enter 1s var(--sileo-spring-easing) both}[data-sileo-header-inner][data-layer=prev]{position:absolute;left:0;top:0;pointer-events:none}[data-sileo-header-inner][data-exiting=true]{animation:sileo-header-exit 150ms ease forwards}[data-sileo-badge]{display:flex;height:24px;width:24px;flex-shrink:0;align-items:center;justify-content:center;padding:2px;box-sizing:border-box;border-radius:9999px;color:var(--sileo-tone,currentColor);background-color:var(--sileo-tone-bg,transparent)}[data-sileo-title]{font-size:.825rem;line-height:1rem;font-weight:500;text-transform:capitalize;color:var(--sileo-tone,currentColor)}:is([data-sileo-badge],[data-sileo-title])[data-state]{--_c:var(--sileo-state-success);--sileo-tone:var(--_c);--sileo-tone-bg:color-mix(in oklch, var(--_c) 20%, transparent)}:is([data-sileo-badge],[data-sileo-title])[data-state=loading]{--_c:var(--sileo-state-loading)}:is([data-sileo-badge],[data-sileo-title])[data-state=error]{--_c:var(--sileo-state-error)}:is([data-sileo-badge],[data-sileo-title])[data-state=warning]{--_c:var(--sileo-state-warning)}:is([data-sileo-badge],[data-sileo-title])[data-state=info]{--_c:var(--sileo-state-info)}:is([data-sileo-badge],[data-sileo-title])[data-state=action]{--_c:var(--sileo-state-action)}[data-sileo-content]{position:absolute;left:0;z-index:10;width:100%;pointer-events:none}[data-sileo-toast][data-ready=true] [data-sileo-content]{transition:opacity calc(var(--sileo-duration) * .08) var(--sileo-spring-easing) calc(var(--sileo-duration) * .04)}[data-sileo-content][data-edge=top]{top:0}[data-sileo-content][data-edge=bottom]{top:var(--sileo-height)}[data-sileo-content][data-visible=true]{pointer-events:auto}[data-sileo-toast][data-ready=true] [data-sileo-content][data-visible=true]{transition:opacity var(--sileo-duration) var(--sileo-spring-easing) calc(var(--sileo-duration) * .25)}[data-sileo-description]{width:100%;text-align:left;padding:1rem;font-size:.875rem;line-height:1.25rem;contain:layout style;content-visibility:auto}[data-sileo-button]{display:flex;align-items:center;justify-content:center;height:1.75rem;padding:0 .625rem;margin-top:.75rem;border-radius:9999px;border:0;font-size:.75rem;font-weight:500;cursor:pointer;color:var(--sileo-btn-color,currentColor);background-color:var(--sileo-btn-bg,transparent);transition:background-color 150ms ease}[data-sileo-button]:hover{background-color:var(--sileo-btn-bg-hover,transparent)}[data-sileo-button][data-state]{--_c:var(--sileo-state-success);--sileo-btn-color:var(--_c);--sileo-btn-bg:color-mix(in oklch, var(--_c) 15%, transparent);--sileo-btn-bg-hover:color-mix(in oklch, var(--_c) 25%, transparent)}[data-sileo-button][data-state=loading]{--_c:var(--sileo-state-loading)}[data-sileo-button][data-state=error]{--_c:var(--sileo-state-error)}[data-sileo-button][data-state=warning]{--_c:var(--sileo-state-warning)}[data-sileo-button][data-state=info]{--_c:var(--sileo-state-info)}[data-sileo-button][data-state=action]{--_c:var(--sileo-state-action)}[data-sileo-icon=spin]{animation:sileo-spin 1s linear infinite}@keyframes sileo-spin{to{rotate:360deg}}@keyframes sileo-header-enter{from{opacity:0;filter:blur(6px)}to{opacity:1;filter:blur(0px)}}@keyframes sileo-header-exit{from{opacity:1;filter:blur(0px)}to{opacity:0;filter:blur(6px)}}[data-sileo-viewport]{position:fixed;z-index:50;display:flex;gap:.75rem;padding:.75rem;pointer-events:none;max-width:calc(100vw - 1.5rem);contain:layout style}[data-sileo-viewport][data-position^=top] [data-sileo-toast]:not([data-ready=true]){margin-bottom:calc(-1 * (var(--sileo-height) + .75rem))}[data-sileo-viewport][data-position^=bottom] [data-sileo-toast]:not([data-ready=true]){margin-top:calc(-1 * (var(--sileo-height) + .75rem))}[data-sileo-viewport][data-position^=top]{top:0;flex-direction:column-reverse}[data-sileo-viewport][data-position^=bottom]{bottom:0;flex-direction:column}[data-sileo-viewport][data-position$=left]{left:0;align-items:flex-start}[data-sileo-viewport][data-position$=right]{right:0;align-items:flex-end}[data-sileo-viewport][data-position$=center]{left:50%;transform:translateX(-50%);align-items:center}@media (prefers-reduced-motion:no-preference){[data-sileo-toast][data-ready=true]{will-change:transform,opacity}[data-sileo-toast][data-ready=true][data-expanded=true]{will-change:transform,opacity,height}[data-sileo-body],[data-sileo-pill]{will-change:transform}[data-sileo-canvas]{will-change:filter}}@media (prefers-reduced-motion:reduce){*,::after,::before{animation-duration:0s;animation-iteration-count:1;transition-duration:0s}}");
|
|
15
|
+
__insertCSS(":root{--sileo-spring-easing:linear(\n\t\t0,\n\t\t0.002 0.6%,\n\t\t0.007 1.2%,\n\t\t0.015 1.8%,\n\t\t0.025 2.4%,\n\t\t0.057 3.7%,\n\t\t0.104 5.2%,\n\t\t0.151 6.5%,\n\t\t0.208 7.9%,\n\t\t0.455 13.6%,\n\t\t0.566 16.3%,\n\t\t0.619 17.7%,\n\t\t0.669 19.1%,\n\t\t0.715 20.5%,\n\t\t0.755 21.8%,\n\t\t0.794 23.2%,\n\t\t0.829 24.6%,\n\t\t0.861 26%,\n\t\t0.889 27.4%,\n\t\t0.914 28.8%,\n\t\t0.937 30.3%,\n\t\t0.956 31.8%,\n\t\t0.974 33.4%,\n\t\t0.987 34.8%,\n\t\t0.997 36.2%,\n\t\t1.014 39.2%,\n\t\t1.024 42.5%,\n\t\t1.028 46.3%,\n\t\t1.026 51.9%,\n\t\t1.01 66.1%,\n\t\t1.003 74.9%,\n\t\t1 85.2%,\n\t\t1\n\t);--sileo-duration:600ms;--sileo-height:40px;--sileo-width:350px;--sileo-state-success:oklch(0.723 0.219 142.136);--sileo-state-loading:oklch(0.556 0 0);--sileo-state-error:oklch(0.637 0.237 25.331);--sileo-state-warning:oklch(0.795 0.184 86.047);--sileo-state-info:oklch(0.685 0.169 237.323);--sileo-state-action:oklch(0.623 0.214 259.815)}[data-sileo-toast]{position:relative;cursor:pointer;pointer-events:auto;touch-action:none;border:0;background:0 0;padding:0;width:var(--sileo-width);height:var(--sileo-button-height,var(--sileo-height));opacity:0;transform:translateZ(0) scale(.95);transform-origin:center;filter:drop-shadow(0 0 8px rgba(0, 0, 0, .05));contain:layout style;overflow:visible}[data-sileo-toast][data-state=loading]{cursor:default}[data-sileo-toast][data-ready=true]{opacity:1;transform:translateZ(0) scale(1);transition:transform calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),opacity calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),margin-bottom calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),margin-top calc(var(--sileo-duration) * .66) var(--sileo-spring-easing),height var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-viewport][data-position^=top] [data-sileo-toast]:not([data-ready=true]){transform:translateY(-6px) scale(.95)}[data-sileo-viewport][data-position^=bottom] [data-sileo-toast]:not([data-ready=true]){transform:translateY(6px) scale(.95)}[data-sileo-toast][data-ready=true][data-exiting=true]{opacity:0;pointer-events:none}[data-sileo-viewport][data-position^=top] [data-sileo-toast][data-ready=true][data-exiting=true]{transform:translateY(-6px) scale(.95)}[data-sileo-viewport][data-position^=bottom] [data-sileo-toast][data-ready=true][data-exiting=true]{transform:translateY(6px) scale(.95)}[data-sileo-canvas]{position:absolute;left:0;right:0;pointer-events:none;transform:translateZ(0);contain:layout style;overflow:visible}[data-sileo-canvas][data-edge=top]{bottom:0;transform:scaleY(-1) translateZ(0)}[data-sileo-canvas][data-edge=bottom]{top:0}[data-sileo-svg]{overflow:visible}[data-sileo-body],[data-sileo-pill]{transform-box:fill-box;transform-origin:50% 0%}[data-sileo-toast][data-ready=true] [data-sileo-pill]{transition:transform var(--sileo-duration) var(--sileo-spring-easing),width var(--sileo-duration) var(--sileo-spring-easing),height var(--sileo-duration) var(--sileo-spring-easing),x var(--sileo-duration) var(--sileo-spring-easing),fill var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-toast][data-ready=true][data-expanded=true] [data-sileo-pill]{transition-delay:calc(var(--sileo-duration) * 0.08)}[data-sileo-toast][data-ready=true] [data-sileo-body]{transition:transform var(--sileo-duration) var(--sileo-spring-easing),opacity var(--sileo-duration) var(--sileo-spring-easing),fill var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-header]{position:absolute;z-index:20;display:flex;align-items:center;padding:.5rem;height:var(--sileo-height);overflow:hidden}[data-sileo-toast][data-ready=true] [data-sileo-header]{max-width:var(--sileo-pill-width);transition:transform var(--sileo-duration) var(--sileo-spring-easing),left var(--sileo-duration) var(--sileo-spring-easing),max-width var(--sileo-duration) var(--sileo-spring-easing)}[data-sileo-header][data-edge=top]{bottom:0}[data-sileo-header][data-edge=bottom]{top:0}[data-sileo-header-stack]{position:relative;display:inline-flex;align-items:center;height:100%}[data-sileo-header-inner]{display:flex;align-items:center;gap:.5rem;white-space:nowrap;opacity:1;filter:blur(0px)}[data-sileo-header-inner][data-layer=current]{animation:sileo-header-enter 1s var(--sileo-spring-easing) both}[data-sileo-header-inner][data-layer=prev]{position:absolute;left:0;top:0;pointer-events:none}[data-sileo-header-inner][data-exiting=true]{animation:sileo-header-exit 150ms ease forwards}[data-sileo-badge]{display:flex;height:24px;width:24px;flex-shrink:0;align-items:center;justify-content:center;padding:2px;box-sizing:border-box;border-radius:9999px;color:var(--sileo-tone,currentColor);background-color:var(--sileo-tone-bg,transparent)}[data-sileo-title]{font-size:.825rem;line-height:1rem;font-weight:500;text-transform:capitalize;color:var(--sileo-tone,currentColor)}:is([data-sileo-badge],[data-sileo-title])[data-state]{--_c:var(--sileo-state-success);--sileo-tone:var(--_c);--sileo-tone-bg:color-mix(in oklch, var(--_c) 20%, transparent)}:is([data-sileo-badge],[data-sileo-title])[data-state=loading]{--_c:var(--sileo-state-loading)}:is([data-sileo-badge],[data-sileo-title])[data-state=error]{--_c:var(--sileo-state-error)}:is([data-sileo-badge],[data-sileo-title])[data-state=warning]{--_c:var(--sileo-state-warning)}:is([data-sileo-badge],[data-sileo-title])[data-state=info]{--_c:var(--sileo-state-info)}:is([data-sileo-badge],[data-sileo-title])[data-state=action]{--_c:var(--sileo-state-action)}[data-sileo-content]{position:absolute;left:0;z-index:10;width:100%;pointer-events:none}[data-sileo-toast][data-ready=true] [data-sileo-content]{transition:opacity calc(var(--sileo-duration) * .08) var(--sileo-spring-easing) calc(var(--sileo-duration) * .04)}[data-sileo-content][data-edge=top]{top:0}[data-sileo-content][data-edge=bottom]{top:var(--sileo-height)}[data-sileo-content][data-visible=true]{pointer-events:auto}[data-sileo-toast][data-ready=true] [data-sileo-content][data-visible=true]{transition:opacity var(--sileo-duration) var(--sileo-spring-easing) calc(var(--sileo-duration) * .25)}[data-sileo-description]{width:100%;text-align:left;padding:1rem;font-size:.875rem;line-height:1.25rem;contain:layout style;content-visibility:auto}[data-sileo-button]{display:flex;align-items:center;justify-content:center;height:1.75rem;padding:0 .625rem;margin-top:.75rem;border-radius:9999px;border:0;font-size:.75rem;font-weight:500;cursor:pointer;color:var(--sileo-btn-color,currentColor);background-color:var(--sileo-btn-bg,transparent);transition:background-color 150ms ease}[data-sileo-button]:hover{background-color:var(--sileo-btn-bg-hover,transparent)}[data-sileo-button][data-state]{--_c:var(--sileo-state-success);--sileo-btn-color:var(--_c);--sileo-btn-bg:color-mix(in oklch, var(--_c) 15%, transparent);--sileo-btn-bg-hover:color-mix(in oklch, var(--_c) 25%, transparent)}[data-sileo-button][data-state=loading]{--_c:var(--sileo-state-loading)}[data-sileo-button][data-state=error]{--_c:var(--sileo-state-error)}[data-sileo-button][data-state=warning]{--_c:var(--sileo-state-warning)}[data-sileo-button][data-state=info]{--_c:var(--sileo-state-info)}[data-sileo-button][data-state=action]{--_c:var(--sileo-state-action)}[data-sileo-icon=spin]{animation:sileo-spin 1s linear infinite}@keyframes sileo-spin{to{rotate:360deg}}@keyframes sileo-header-enter{from{opacity:0;filter:blur(6px)}to{opacity:1;filter:blur(0px)}}@keyframes sileo-header-exit{from{opacity:1;filter:blur(0px)}to{opacity:0;filter:blur(6px)}}[data-sileo-viewport]{position:fixed;z-index:50;display:flex;gap:.75rem;padding:.75rem;pointer-events:none;max-width:calc(100vw - 1.5rem);contain:layout style}[data-sileo-viewport][data-position^=top] [data-sileo-toast]:not([data-ready=true]){margin-bottom:calc(-1 * (var(--sileo-height) + .75rem))}[data-sileo-viewport][data-position^=bottom] [data-sileo-toast]:not([data-ready=true]){margin-top:calc(-1 * (var(--sileo-height) + .75rem))}[data-sileo-viewport][data-position^=top]{top:0;flex-direction:column-reverse}[data-sileo-viewport][data-position^=bottom]{bottom:0;flex-direction:column}[data-sileo-viewport][data-position$=left]{left:0;align-items:flex-start}[data-sileo-viewport][data-position$=right]{right:0;align-items:flex-end}[data-sileo-viewport][data-position$=center]{left:50%;transform:translateX(-50%);align-items:center}@media (prefers-reduced-motion:no-preference){[data-sileo-toast][data-ready=true]{will-change:transform,opacity}[data-sileo-toast][data-ready=true][data-expanded=true]{will-change:transform,opacity,height}[data-sileo-body],[data-sileo-pill]{will-change:transform}[data-sileo-canvas]{will-change:filter}}@media (prefers-reduced-motion:reduce){*,::after,::before{animation-duration:0s;animation-iteration-count:1;transition-duration:0s}}");
|
|
16
16
|
|
|
17
17
|
const ArrowRight = ()=>/*#__PURE__*/ jsxs("svg", {
|
|
18
18
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -217,7 +217,7 @@ const HEADER_EXIT_MS = 150;
|
|
|
217
217
|
})
|
|
218
218
|
});
|
|
219
219
|
});
|
|
220
|
-
/* ------------------------------- Component -------------------------------- */ const Sileo = /*#__PURE__*/ memo(function Sileo({ id, fill = "#FFFFFF", state = "success", title = state, description, position = "left", expand = "bottom", className, icon, styles, button, roundness, exiting = false, autoExpandDelayMs, autoCollapseDelayMs, canExpand, interruptKey, refreshKey, onMouseEnter, onMouseLeave }) {
|
|
220
|
+
/* ------------------------------- Component -------------------------------- */ const Sileo = /*#__PURE__*/ memo(function Sileo({ id, fill = "#FFFFFF", state = "success", title = state, description, position = "left", expand = "bottom", className, icon, styles, button, roundness, exiting = false, autoExpandDelayMs, autoCollapseDelayMs, canExpand, interruptKey, refreshKey, onMouseEnter, onMouseLeave, onDismiss }) {
|
|
221
221
|
var _headerLayer_current_view_icon, _headerLayer_prev_view_icon;
|
|
222
222
|
var _headerLayer_current_view_styles, _headerLayer_current_view_styles1, _headerLayer_prev_view_styles, _headerLayer_prev_view_styles1, _view_styles, _view_styles1;
|
|
223
223
|
const next = useMemo(()=>({
|
|
@@ -501,7 +501,48 @@ const HEADER_EXIT_MS = 150;
|
|
|
501
501
|
}, [
|
|
502
502
|
open
|
|
503
503
|
]);
|
|
504
|
+
/* -------------------------------- Swipe ----------------------------------- */ const SWIPE_DISMISS = 30;
|
|
505
|
+
const SWIPE_MAX = 20;
|
|
506
|
+
const buttonRef = useRef(null);
|
|
507
|
+
const pointerStartRef = useRef(null);
|
|
508
|
+
const onDismissRef = useRef(onDismiss);
|
|
509
|
+
onDismissRef.current = onDismiss;
|
|
510
|
+
useEffect(()=>{
|
|
511
|
+
const el = buttonRef.current;
|
|
512
|
+
if (!el) return;
|
|
513
|
+
const onMove = (e)=>{
|
|
514
|
+
if (pointerStartRef.current === null) return;
|
|
515
|
+
const dy = e.clientY - pointerStartRef.current;
|
|
516
|
+
const sign = dy > 0 ? 1 : -1;
|
|
517
|
+
const clamped = Math.min(Math.abs(dy), SWIPE_MAX) * sign;
|
|
518
|
+
el.style.transform = `translateY(${clamped}px)`;
|
|
519
|
+
};
|
|
520
|
+
const onUp = (e)=>{
|
|
521
|
+
if (pointerStartRef.current === null) return;
|
|
522
|
+
const dy = e.clientY - pointerStartRef.current;
|
|
523
|
+
pointerStartRef.current = null;
|
|
524
|
+
el.style.transform = "";
|
|
525
|
+
if (Math.abs(dy) > SWIPE_DISMISS) {
|
|
526
|
+
onDismissRef.current == null ? void 0 : onDismissRef.current.call(onDismissRef);
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
el.addEventListener("pointermove", onMove);
|
|
530
|
+
el.addEventListener("pointerup", onUp);
|
|
531
|
+
return ()=>{
|
|
532
|
+
el.removeEventListener("pointermove", onMove);
|
|
533
|
+
el.removeEventListener("pointerup", onUp);
|
|
534
|
+
};
|
|
535
|
+
}, []);
|
|
536
|
+
const handlePointerDown = useCallback((e)=>{
|
|
537
|
+
if (exiting || !onDismiss) return;
|
|
538
|
+
pointerStartRef.current = e.clientY;
|
|
539
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
540
|
+
}, [
|
|
541
|
+
exiting,
|
|
542
|
+
onDismiss
|
|
543
|
+
]);
|
|
504
544
|
/* --------------------------------- Render --------------------------------- */ return /*#__PURE__*/ jsxs("button", {
|
|
545
|
+
ref: buttonRef,
|
|
505
546
|
type: "button",
|
|
506
547
|
"data-sileo-toast": true,
|
|
507
548
|
"data-ready": ready,
|
|
@@ -515,6 +556,7 @@ const HEADER_EXIT_MS = 150;
|
|
|
515
556
|
onMouseEnter: handleEnter,
|
|
516
557
|
onMouseLeave: handleLeave,
|
|
517
558
|
onTransitionEnd: handleTransitionEnd,
|
|
559
|
+
onPointerDown: handlePointerDown,
|
|
518
560
|
children: [
|
|
519
561
|
/*#__PURE__*/ jsx("div", {
|
|
520
562
|
"data-sileo-canvas": true,
|
|
@@ -717,7 +759,7 @@ const createToast = (options)=>{
|
|
|
717
759
|
store.update((p)=>p.map((t)=>t.id === id ? item : t));
|
|
718
760
|
} else {
|
|
719
761
|
store.update((p)=>[
|
|
720
|
-
...p,
|
|
762
|
+
...p.filter((t)=>t.id !== id),
|
|
721
763
|
item
|
|
722
764
|
]);
|
|
723
765
|
}
|
|
@@ -752,7 +794,8 @@ const sileo = {
|
|
|
752
794
|
promise: (promise, opts)=>{
|
|
753
795
|
const { id } = createToast(_extends({}, opts.loading, {
|
|
754
796
|
state: "loading",
|
|
755
|
-
duration: null
|
|
797
|
+
duration: null,
|
|
798
|
+
position: opts.position
|
|
756
799
|
}));
|
|
757
800
|
const p = typeof promise === "function" ? promise() : promise;
|
|
758
801
|
p.then((data)=>{
|
|
@@ -881,7 +924,8 @@ const sileo = {
|
|
|
881
924
|
leave: (e)=>{
|
|
882
925
|
setActiveId((prev)=>prev === latestRef.current ? prev : latestRef.current);
|
|
883
926
|
handleMouseLeaveRef.current == null ? void 0 : handleMouseLeaveRef.current.call(handleMouseLeaveRef, e);
|
|
884
|
-
}
|
|
927
|
+
},
|
|
928
|
+
dismiss: ()=>dismissToast(toastId)
|
|
885
929
|
};
|
|
886
930
|
handlersCache.current.set(toastId, cached);
|
|
887
931
|
return cached;
|
|
@@ -956,7 +1000,8 @@ const sileo = {
|
|
|
956
1000
|
refreshKey: item.instanceId,
|
|
957
1001
|
canExpand: activeId === undefined || activeId === item.id,
|
|
958
1002
|
onMouseEnter: h.enter,
|
|
959
|
-
onMouseLeave: h.leave
|
|
1003
|
+
onMouseLeave: h.leave,
|
|
1004
|
+
onDismiss: h.dismiss
|
|
960
1005
|
}, item.id);
|
|
961
1006
|
})
|
|
962
1007
|
}, pos);
|
package/dist/styles.css
CHANGED