foldkit 0.69.0 → 0.71.0
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/ui/index.d.ts +2 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +2 -0
- package/dist/ui/toast/index.d.ts +620 -0
- package/dist/ui/toast/index.d.ts.map +1 -0
- package/dist/ui/toast/index.js +158 -0
- package/dist/ui/toast/public.d.ts +4 -0
- package/dist/ui/toast/public.d.ts.map +1 -0
- package/dist/ui/toast/public.js +1 -0
- package/dist/ui/toast/schema.d.ts +143 -0
- package/dist/ui/toast/schema.d.ts.map +1 -0
- package/dist/ui/toast/schema.js +71 -0
- package/dist/ui/toast/update.d.ts +484 -0
- package/dist/ui/toast/update.d.ts.map +1 -0
- package/dist/ui/toast/update.js +203 -0
- package/dist/ui/tooltip/index.d.ts +96 -0
- package/dist/ui/tooltip/index.d.ts.map +1 -0
- package/dist/ui/tooltip/index.js +244 -0
- package/dist/ui/tooltip/public.d.ts +4 -0
- package/dist/ui/tooltip/public.d.ts.map +1 -0
- package/dist/ui/tooltip/public.js +1 -0
- package/package.json +9 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { Match as M } from 'effect';
|
|
2
|
+
import { createLazy, html } from '../../html';
|
|
3
|
+
import { Dismissed, DismissedAll, ElapsedDuration, GotTransitionMessage, HoveredEntry, LeftEntry, Position, Variant, } from './schema';
|
|
4
|
+
import { DismissAfter, makeRuntime } from './update';
|
|
5
|
+
export { Variant, Position, Dismissed, DismissedAll, ElapsedDuration, HoveredEntry, LeftEntry, GotTransitionMessage, DismissAfter, };
|
|
6
|
+
const variantToRole = (variant) => M.value(variant).pipe(M.withReturnType(), M.when('Info', () => 'status'), M.when('Success', () => 'status'), M.when('Warning', () => 'alert'), M.when('Error', () => 'alert'), M.exhaustive);
|
|
7
|
+
const positionToContainerStyle = (position) => {
|
|
8
|
+
const base = {
|
|
9
|
+
position: 'fixed',
|
|
10
|
+
display: 'flex',
|
|
11
|
+
gap: '8px',
|
|
12
|
+
padding: '16px',
|
|
13
|
+
margin: '0',
|
|
14
|
+
listStyle: 'none',
|
|
15
|
+
pointerEvents: 'none',
|
|
16
|
+
zIndex: '2147483600',
|
|
17
|
+
};
|
|
18
|
+
return M.value(position).pipe(M.withReturnType(), M.when('TopLeft', () => ({
|
|
19
|
+
...base,
|
|
20
|
+
top: '0',
|
|
21
|
+
left: '0',
|
|
22
|
+
flexDirection: 'column-reverse',
|
|
23
|
+
})), M.when('TopCenter', () => ({
|
|
24
|
+
...base,
|
|
25
|
+
top: '0',
|
|
26
|
+
left: '50%',
|
|
27
|
+
transform: 'translateX(-50%)',
|
|
28
|
+
flexDirection: 'column-reverse',
|
|
29
|
+
})), M.when('TopRight', () => ({
|
|
30
|
+
...base,
|
|
31
|
+
top: '0',
|
|
32
|
+
right: '0',
|
|
33
|
+
flexDirection: 'column-reverse',
|
|
34
|
+
})), M.when('BottomLeft', () => ({
|
|
35
|
+
...base,
|
|
36
|
+
bottom: '0',
|
|
37
|
+
left: '0',
|
|
38
|
+
flexDirection: 'column',
|
|
39
|
+
})), M.when('BottomCenter', () => ({
|
|
40
|
+
...base,
|
|
41
|
+
bottom: '0',
|
|
42
|
+
left: '50%',
|
|
43
|
+
transform: 'translateX(-50%)',
|
|
44
|
+
flexDirection: 'column',
|
|
45
|
+
})), M.when('BottomRight', () => ({
|
|
46
|
+
...base,
|
|
47
|
+
bottom: '0',
|
|
48
|
+
right: '0',
|
|
49
|
+
flexDirection: 'column',
|
|
50
|
+
})), M.exhaustive);
|
|
51
|
+
};
|
|
52
|
+
const DEFAULT_ARIA_LABEL = 'Notifications';
|
|
53
|
+
/** Factory that binds `Ui.Toast` to a user-provided payload schema. The
|
|
54
|
+
* returned module contains everything needed to wire a toast stack into an
|
|
55
|
+
* app: `Model`, `Message`, `Entry`, `Added`, `init`, `update`, `show` /
|
|
56
|
+
* `dismiss` / `dismissAll` helpers, and the headless `view`.
|
|
57
|
+
*
|
|
58
|
+
* The payload is whatever content shape the consumer supplies via Schema.
|
|
59
|
+
* The component never reads it — it flows through to `renderEntry`. The
|
|
60
|
+
* component itself owns only lifecycle and a11y fields (id, variant,
|
|
61
|
+
* transition, dismiss timer, hover state).
|
|
62
|
+
*
|
|
63
|
+
* Consume the bound module's exports everywhere — `Toast.Model` in your app
|
|
64
|
+
* Model, `Toast.Message` in your parent Message union, `Toast.show` /
|
|
65
|
+
* `Toast.dismiss` in your update, `Toast.view` in your view. The top-level
|
|
66
|
+
* exports (`Variant`, `Position`, static message tags, `DismissAfter`) are
|
|
67
|
+
* payload-independent and safe to reference when you need them without a
|
|
68
|
+
* bound module, but the typical path is through the factory return.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* const ToastPayload = S.Struct({
|
|
73
|
+
* bodyText: S.String,
|
|
74
|
+
* maybeLink: S.OptionFromSelf(S.Struct({
|
|
75
|
+
* href: S.String,
|
|
76
|
+
* text: S.String,
|
|
77
|
+
* })),
|
|
78
|
+
* })
|
|
79
|
+
* export const Toast = Ui.Toast.make(ToastPayload)
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export const make = (payloadSchema) => {
|
|
83
|
+
const runtime = makeRuntime(payloadSchema);
|
|
84
|
+
/** Renders a headless toast stack. The `<ol>` container is always present
|
|
85
|
+
* in the DOM so screen readers can observe its `aria-live` region from
|
|
86
|
+
* page load. Each entry becomes an `<li>` keyed by its id, with
|
|
87
|
+
* transition data attributes (`data-enter`, `data-leave`,
|
|
88
|
+
* `data-transition`, `data-closed`) and `data-variant` reflecting the
|
|
89
|
+
* entry's variant. */
|
|
90
|
+
const view = (config) => {
|
|
91
|
+
const { AriaAtomic, AriaLabel, AriaLive, Class, DataAttribute, Id, OnMouseEnter, OnMouseLeave, Role, Style, keyed, } = html();
|
|
92
|
+
const { model: { id, entries }, position, toParentMessage, renderEntry, ariaLabel = DEFAULT_ARIA_LABEL, className, attributes = [], entryClassName, entryAttributes = [], } = config;
|
|
93
|
+
const containerAttributes = [
|
|
94
|
+
Id(id),
|
|
95
|
+
Role('region'),
|
|
96
|
+
AriaLabel(ariaLabel),
|
|
97
|
+
AriaLive('polite'),
|
|
98
|
+
Style(positionToContainerStyle(position)),
|
|
99
|
+
...(className ? [Class(className)] : []),
|
|
100
|
+
...attributes,
|
|
101
|
+
];
|
|
102
|
+
const renderEntryItem = (entry) => {
|
|
103
|
+
const { transitionState } = entry.transition;
|
|
104
|
+
const transitionAttributes = M.value(transitionState).pipe(M.when('EnterStart', () => [
|
|
105
|
+
DataAttribute('closed', ''),
|
|
106
|
+
DataAttribute('enter', ''),
|
|
107
|
+
DataAttribute('transition', ''),
|
|
108
|
+
]), M.when('EnterAnimating', () => [
|
|
109
|
+
DataAttribute('enter', ''),
|
|
110
|
+
DataAttribute('transition', ''),
|
|
111
|
+
]), M.when('LeaveStart', () => [
|
|
112
|
+
DataAttribute('leave', ''),
|
|
113
|
+
DataAttribute('transition', ''),
|
|
114
|
+
]), M.when('LeaveAnimating', () => [
|
|
115
|
+
DataAttribute('closed', ''),
|
|
116
|
+
DataAttribute('leave', ''),
|
|
117
|
+
DataAttribute('transition', ''),
|
|
118
|
+
]), M.orElse(() => []));
|
|
119
|
+
const handlers = {
|
|
120
|
+
dismiss: toParentMessage(Dismissed({ entryId: entry.id })),
|
|
121
|
+
};
|
|
122
|
+
const itemAttributes = [
|
|
123
|
+
Id(entry.id),
|
|
124
|
+
Role(variantToRole(entry.variant)),
|
|
125
|
+
AriaAtomic(true),
|
|
126
|
+
DataAttribute('variant', entry.variant),
|
|
127
|
+
Style({ pointerEvents: 'auto' }),
|
|
128
|
+
OnMouseEnter(toParentMessage(HoveredEntry({ entryId: entry.id }))),
|
|
129
|
+
OnMouseLeave(toParentMessage(LeftEntry({ entryId: entry.id }))),
|
|
130
|
+
...transitionAttributes,
|
|
131
|
+
...(entryClassName ? [Class(entryClassName)] : []),
|
|
132
|
+
...entryAttributes,
|
|
133
|
+
];
|
|
134
|
+
return keyed('li')(entry.id, itemAttributes, [
|
|
135
|
+
renderEntry(entry, handlers),
|
|
136
|
+
]);
|
|
137
|
+
};
|
|
138
|
+
return keyed('ol')(id, containerAttributes, entries.map(renderEntryItem));
|
|
139
|
+
};
|
|
140
|
+
/** Creates a memoized toast container view. Static config (className,
|
|
141
|
+
* entryClassName, etc.) is captured in a closure. Dynamic fields —
|
|
142
|
+
* `model`, `toParentMessage`, and `renderEntry` — are compared by
|
|
143
|
+
* reference per render via `createLazy`. */
|
|
144
|
+
const lazy = (staticConfig) => {
|
|
145
|
+
const lazyView = createLazy();
|
|
146
|
+
return (model, toParentMessage, renderEntry) => lazyView((currentModel, currentToMessage, currentRenderEntry) => view({
|
|
147
|
+
...staticConfig,
|
|
148
|
+
model: currentModel,
|
|
149
|
+
toParentMessage: currentToMessage,
|
|
150
|
+
renderEntry: currentRenderEntry,
|
|
151
|
+
}), [model, toParentMessage, renderEntry]);
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
...runtime,
|
|
155
|
+
view,
|
|
156
|
+
lazy,
|
|
157
|
+
};
|
|
158
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { make, Variant, Position, Dismissed, DismissedAll, ElapsedDuration, HoveredEntry, LeftEntry, GotTransitionMessage, DismissAfter, } from './index';
|
|
2
|
+
export type { EntryHandlers } from './index';
|
|
3
|
+
export type { InitConfig, ShowInput } from './index';
|
|
4
|
+
//# sourceMappingURL=public.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/toast/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,SAAS,EACT,oBAAoB,EACpB,YAAY,GACb,MAAM,SAAS,CAAA;AAEhB,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { make, Variant, Position, Dismissed, DismissedAll, ElapsedDuration, HoveredEntry, LeftEntry, GotTransitionMessage, DismissAfter, } from './index';
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Duration, Schema as S } from 'effect';
|
|
2
|
+
/** Semantic category of a toast. Drives the default ARIA role: `status` for
|
|
3
|
+
* `Info` / `Success`, `alert` for `Warning` / `Error`. Also surfaced as
|
|
4
|
+
* `data-variant` on each entry for per-variant CSS. This is the only
|
|
5
|
+
* content-adjacent field the component owns — the rest of the entry's
|
|
6
|
+
* content lives in the user-provided payload. */
|
|
7
|
+
export declare const Variant: S.Literal<["Info", "Success", "Warning", "Error"]>;
|
|
8
|
+
export type Variant = typeof Variant.Type;
|
|
9
|
+
/** Where the toast viewport is anchored on the screen and how entries stack. */
|
|
10
|
+
export declare const Position: S.Literal<["TopLeft", "TopCenter", "TopRight", "BottomLeft", "BottomCenter", "BottomRight"]>;
|
|
11
|
+
export type Position = typeof Position.Type;
|
|
12
|
+
/** Schema factory for a single toast entry. `payloadSchema` is user-provided
|
|
13
|
+
* and defines the shape of per-entry content — whatever the consumer wants
|
|
14
|
+
* to encode. The component itself owns only lifecycle + a11y fields: `id`,
|
|
15
|
+
* `variant` (for ARIA role), `transition`, `maybeDuration`,
|
|
16
|
+
* `pendingDismissVersion` (for cancellable auto-dismiss), and `isHovered`
|
|
17
|
+
* (for pause-on-hover). */
|
|
18
|
+
export declare const makeEntry: <A, I>(payloadSchema: S.Schema<A, I>) => S.Struct<{
|
|
19
|
+
id: typeof S.String;
|
|
20
|
+
variant: S.Literal<["Info", "Success", "Warning", "Error"]>;
|
|
21
|
+
transition: S.Struct<{
|
|
22
|
+
id: typeof S.String;
|
|
23
|
+
isShowing: typeof S.Boolean;
|
|
24
|
+
transitionState: S.Literal<["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>;
|
|
25
|
+
}>;
|
|
26
|
+
maybeDuration: S.OptionFromSelf<typeof S.DurationFromMillis>;
|
|
27
|
+
pendingDismissVersion: typeof S.Number;
|
|
28
|
+
isHovered: typeof S.Boolean;
|
|
29
|
+
payload: S.Schema<A, I, never>;
|
|
30
|
+
}>;
|
|
31
|
+
/** Schema factory for the toast container's state. `nextEntryKey` is a
|
|
32
|
+
* monotonic counter used to generate unique entry IDs purely from Model
|
|
33
|
+
* state. Thread the updated model through successive `show()` calls —
|
|
34
|
+
* calling `show()` twice against the same pre-update model in the same tick
|
|
35
|
+
* will produce duplicate entry IDs. */
|
|
36
|
+
export declare const makeModel: <A, I>(payloadSchema: S.Schema<A, I>) => S.Struct<{
|
|
37
|
+
id: typeof S.String;
|
|
38
|
+
defaultDuration: typeof S.DurationFromMillis;
|
|
39
|
+
entries: S.Array$<S.Struct<{
|
|
40
|
+
id: typeof S.String;
|
|
41
|
+
variant: S.Literal<["Info", "Success", "Warning", "Error"]>;
|
|
42
|
+
transition: S.Struct<{
|
|
43
|
+
id: typeof S.String;
|
|
44
|
+
isShowing: typeof S.Boolean;
|
|
45
|
+
transitionState: S.Literal<["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>;
|
|
46
|
+
}>;
|
|
47
|
+
maybeDuration: S.OptionFromSelf<typeof S.DurationFromMillis>;
|
|
48
|
+
pendingDismissVersion: typeof S.Number;
|
|
49
|
+
isHovered: typeof S.Boolean;
|
|
50
|
+
payload: S.Schema<A, I, never>;
|
|
51
|
+
}>>;
|
|
52
|
+
nextEntryKey: typeof S.Number;
|
|
53
|
+
}>;
|
|
54
|
+
/** Sent when an entry should begin dismissing. Starts the leave animation;
|
|
55
|
+
* the entry is removed from the stack when `TransitionedOut` fires. */
|
|
56
|
+
export declare const Dismissed: import("../../schema").CallableTaggedStruct<"Dismissed", {
|
|
57
|
+
entryId: typeof S.String;
|
|
58
|
+
}>;
|
|
59
|
+
/** Sent when every currently-visible entry should begin dismissing. */
|
|
60
|
+
export declare const DismissedAll: import("../../schema").CallableTaggedStruct<"DismissedAll", {}>;
|
|
61
|
+
/** Sent when an entry's auto-dismiss timer fires. Carries a version echoed
|
|
62
|
+
* from the scheduling moment so stale timers (from hover or manual dismiss)
|
|
63
|
+
* are discarded. */
|
|
64
|
+
export declare const ElapsedDuration: import("../../schema").CallableTaggedStruct<"ElapsedDuration", {
|
|
65
|
+
entryId: typeof S.String;
|
|
66
|
+
version: typeof S.Number;
|
|
67
|
+
}>;
|
|
68
|
+
/** Sent when the pointer enters an entry. Pauses the auto-dismiss timer by
|
|
69
|
+
* advancing the entry's version. */
|
|
70
|
+
export declare const HoveredEntry: import("../../schema").CallableTaggedStruct<"HoveredEntry", {
|
|
71
|
+
entryId: typeof S.String;
|
|
72
|
+
}>;
|
|
73
|
+
/** Sent when the pointer leaves an entry. Restarts the auto-dismiss timer
|
|
74
|
+
* with the entry's full duration. */
|
|
75
|
+
export declare const LeftEntry: import("../../schema").CallableTaggedStruct<"LeftEntry", {
|
|
76
|
+
entryId: typeof S.String;
|
|
77
|
+
}>;
|
|
78
|
+
/** Wraps a single entry's Transition submodel message for delegation. */
|
|
79
|
+
export declare const GotTransitionMessage: import("../../schema").CallableTaggedStruct<"GotTransitionMessage", {
|
|
80
|
+
entryId: typeof S.String;
|
|
81
|
+
message: S.Union<[import("../../schema").CallableTaggedStruct<"Showed", {}>, import("../../schema").CallableTaggedStruct<"Hid", {}>, import("../../schema").CallableTaggedStruct<"AdvancedTransitionFrame", {}>, import("../../schema").CallableTaggedStruct<"EndedTransition", {}>]>;
|
|
82
|
+
}>;
|
|
83
|
+
export type Dismissed = typeof Dismissed.Type;
|
|
84
|
+
export type DismissedAll = typeof DismissedAll.Type;
|
|
85
|
+
export type ElapsedDuration = typeof ElapsedDuration.Type;
|
|
86
|
+
export type HoveredEntry = typeof HoveredEntry.Type;
|
|
87
|
+
export type LeftEntry = typeof LeftEntry.Type;
|
|
88
|
+
export type GotTransitionMessage = typeof GotTransitionMessage.Type;
|
|
89
|
+
/** Factory for the `Added` message, which carries a fully-constructed entry
|
|
90
|
+
* whose shape depends on the user-provided payload. */
|
|
91
|
+
export declare const makeAdded: <A, I>(payloadSchema: S.Schema<A, I>) => import("../../schema").CallableTaggedStruct<"Added", {
|
|
92
|
+
entry: S.Struct<{
|
|
93
|
+
id: typeof S.String;
|
|
94
|
+
variant: S.Literal<["Info", "Success", "Warning", "Error"]>;
|
|
95
|
+
transition: S.Struct<{
|
|
96
|
+
id: typeof S.String;
|
|
97
|
+
isShowing: typeof S.Boolean;
|
|
98
|
+
transitionState: S.Literal<["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>;
|
|
99
|
+
}>;
|
|
100
|
+
maybeDuration: S.OptionFromSelf<typeof S.DurationFromMillis>;
|
|
101
|
+
pendingDismissVersion: typeof S.Number;
|
|
102
|
+
isHovered: typeof S.Boolean;
|
|
103
|
+
payload: S.Schema<A, I, never>;
|
|
104
|
+
}>;
|
|
105
|
+
}>;
|
|
106
|
+
/** Factory for the union of all messages the toast component can produce. */
|
|
107
|
+
export declare const makeMessage: <A, I>(payloadSchema: S.Schema<A, I>) => S.Union<[import("../../schema").CallableTaggedStruct<"Added", {
|
|
108
|
+
entry: S.Struct<{
|
|
109
|
+
id: typeof S.String;
|
|
110
|
+
variant: S.Literal<["Info", "Success", "Warning", "Error"]>;
|
|
111
|
+
transition: S.Struct<{
|
|
112
|
+
id: typeof S.String;
|
|
113
|
+
isShowing: typeof S.Boolean;
|
|
114
|
+
transitionState: S.Literal<["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>;
|
|
115
|
+
}>;
|
|
116
|
+
maybeDuration: S.OptionFromSelf<typeof S.DurationFromMillis>;
|
|
117
|
+
pendingDismissVersion: typeof S.Number;
|
|
118
|
+
isHovered: typeof S.Boolean;
|
|
119
|
+
payload: S.Schema<A, I, never>;
|
|
120
|
+
}>;
|
|
121
|
+
}>, import("../../schema").CallableTaggedStruct<"Dismissed", {
|
|
122
|
+
entryId: typeof S.String;
|
|
123
|
+
}>, import("../../schema").CallableTaggedStruct<"DismissedAll", {}>, import("../../schema").CallableTaggedStruct<"ElapsedDuration", {
|
|
124
|
+
entryId: typeof S.String;
|
|
125
|
+
version: typeof S.Number;
|
|
126
|
+
}>, import("../../schema").CallableTaggedStruct<"HoveredEntry", {
|
|
127
|
+
entryId: typeof S.String;
|
|
128
|
+
}>, import("../../schema").CallableTaggedStruct<"LeftEntry", {
|
|
129
|
+
entryId: typeof S.String;
|
|
130
|
+
}>, import("../../schema").CallableTaggedStruct<"GotTransitionMessage", {
|
|
131
|
+
entryId: typeof S.String;
|
|
132
|
+
message: S.Union<[import("../../schema").CallableTaggedStruct<"Showed", {}>, import("../../schema").CallableTaggedStruct<"Hid", {}>, import("../../schema").CallableTaggedStruct<"AdvancedTransitionFrame", {}>, import("../../schema").CallableTaggedStruct<"EndedTransition", {}>]>;
|
|
133
|
+
}>]>;
|
|
134
|
+
/** Configuration for creating a toast container model. `defaultDuration` is
|
|
135
|
+
* applied to any `show()` call that doesn't provide its own `duration` or
|
|
136
|
+
* pass `sticky: true`. Accepts any Effect Duration input; a bare number is
|
|
137
|
+
* interpreted as milliseconds. */
|
|
138
|
+
export type InitConfig = Readonly<{
|
|
139
|
+
id: string;
|
|
140
|
+
defaultDuration?: Duration.DurationInput;
|
|
141
|
+
}>;
|
|
142
|
+
export declare const DEFAULT_DURATION: Duration.Duration;
|
|
143
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/ui/toast/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAU9C;;;;kDAIkD;AAClD,eAAO,MAAM,OAAO,oDAAmD,CAAA;AACvE,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,gFAAgF;AAChF,eAAO,MAAM,QAAQ,8FAOpB,CAAA;AACD,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAI3C;;;;;4BAK4B;AAC5B,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;;;;;;;;;;;;EASzD,CAAA;AAIJ;;;;wCAIwC;AACxC,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;EAMzD,CAAA;AAIJ;wEACwE;AACxE,eAAO,MAAM,SAAS;;EAAwC,CAAA;AAC9D,uEAAuE;AACvE,eAAO,MAAM,YAAY,iEAAoB,CAAA;AAC7C;;qBAEqB;AACrB,eAAO,MAAM,eAAe;;;EAG1B,CAAA;AACF;qCACqC;AACrC,eAAO,MAAM,YAAY;;EAA2C,CAAA;AACpE;sCACsC;AACtC,eAAO,MAAM,SAAS;;EAAwC,CAAA;AAC9D,yEAAyE;AACzE,eAAO,MAAM,oBAAoB;;;EAG/B,CAAA;AAEF,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAC7C,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AACnD,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,IAAI,CAAA;AACzD,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AACnD,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA;AAC7C,MAAM,MAAM,oBAAoB,GAAG,OAAO,oBAAoB,CAAC,IAAI,CAAA;AAEnE;wDACwD;AACxD,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;;;;;;;;;;;;;;EACZ,CAAA;AAEjD,6EAA6E;AAC7E,eAAO,MAAM,WAAW,GAAI,CAAC,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;IAS5D,CAAA;AAIH;;;mCAGmC;AACnC,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,eAAe,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAA;CACzC,CAAC,CAAA;AAEF,eAAO,MAAM,gBAAgB,mBAAsB,CAAA"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Duration, Schema as S } from 'effect';
|
|
2
|
+
import { m } from '../../message';
|
|
3
|
+
import { Message as TransitionMessage, Model as TransitionModel, } from '../transition/schema';
|
|
4
|
+
// VARIANT
|
|
5
|
+
/** Semantic category of a toast. Drives the default ARIA role: `status` for
|
|
6
|
+
* `Info` / `Success`, `alert` for `Warning` / `Error`. Also surfaced as
|
|
7
|
+
* `data-variant` on each entry for per-variant CSS. This is the only
|
|
8
|
+
* content-adjacent field the component owns — the rest of the entry's
|
|
9
|
+
* content lives in the user-provided payload. */
|
|
10
|
+
export const Variant = S.Literal('Info', 'Success', 'Warning', 'Error');
|
|
11
|
+
// POSITION
|
|
12
|
+
/** Where the toast viewport is anchored on the screen and how entries stack. */
|
|
13
|
+
export const Position = S.Literal('TopLeft', 'TopCenter', 'TopRight', 'BottomLeft', 'BottomCenter', 'BottomRight');
|
|
14
|
+
// ENTRY
|
|
15
|
+
/** Schema factory for a single toast entry. `payloadSchema` is user-provided
|
|
16
|
+
* and defines the shape of per-entry content — whatever the consumer wants
|
|
17
|
+
* to encode. The component itself owns only lifecycle + a11y fields: `id`,
|
|
18
|
+
* `variant` (for ARIA role), `transition`, `maybeDuration`,
|
|
19
|
+
* `pendingDismissVersion` (for cancellable auto-dismiss), and `isHovered`
|
|
20
|
+
* (for pause-on-hover). */
|
|
21
|
+
export const makeEntry = (payloadSchema) => S.Struct({
|
|
22
|
+
id: S.String,
|
|
23
|
+
variant: Variant,
|
|
24
|
+
transition: TransitionModel,
|
|
25
|
+
maybeDuration: S.OptionFromSelf(S.DurationFromMillis),
|
|
26
|
+
pendingDismissVersion: S.Number,
|
|
27
|
+
isHovered: S.Boolean,
|
|
28
|
+
payload: payloadSchema,
|
|
29
|
+
});
|
|
30
|
+
// MODEL
|
|
31
|
+
/** Schema factory for the toast container's state. `nextEntryKey` is a
|
|
32
|
+
* monotonic counter used to generate unique entry IDs purely from Model
|
|
33
|
+
* state. Thread the updated model through successive `show()` calls —
|
|
34
|
+
* calling `show()` twice against the same pre-update model in the same tick
|
|
35
|
+
* will produce duplicate entry IDs. */
|
|
36
|
+
export const makeModel = (payloadSchema) => S.Struct({
|
|
37
|
+
id: S.String,
|
|
38
|
+
defaultDuration: S.DurationFromMillis,
|
|
39
|
+
entries: S.Array(makeEntry(payloadSchema)),
|
|
40
|
+
nextEntryKey: S.Number,
|
|
41
|
+
});
|
|
42
|
+
// MESSAGE
|
|
43
|
+
/** Sent when an entry should begin dismissing. Starts the leave animation;
|
|
44
|
+
* the entry is removed from the stack when `TransitionedOut` fires. */
|
|
45
|
+
export const Dismissed = m('Dismissed', { entryId: S.String });
|
|
46
|
+
/** Sent when every currently-visible entry should begin dismissing. */
|
|
47
|
+
export const DismissedAll = m('DismissedAll');
|
|
48
|
+
/** Sent when an entry's auto-dismiss timer fires. Carries a version echoed
|
|
49
|
+
* from the scheduling moment so stale timers (from hover or manual dismiss)
|
|
50
|
+
* are discarded. */
|
|
51
|
+
export const ElapsedDuration = m('ElapsedDuration', {
|
|
52
|
+
entryId: S.String,
|
|
53
|
+
version: S.Number,
|
|
54
|
+
});
|
|
55
|
+
/** Sent when the pointer enters an entry. Pauses the auto-dismiss timer by
|
|
56
|
+
* advancing the entry's version. */
|
|
57
|
+
export const HoveredEntry = m('HoveredEntry', { entryId: S.String });
|
|
58
|
+
/** Sent when the pointer leaves an entry. Restarts the auto-dismiss timer
|
|
59
|
+
* with the entry's full duration. */
|
|
60
|
+
export const LeftEntry = m('LeftEntry', { entryId: S.String });
|
|
61
|
+
/** Wraps a single entry's Transition submodel message for delegation. */
|
|
62
|
+
export const GotTransitionMessage = m('GotTransitionMessage', {
|
|
63
|
+
entryId: S.String,
|
|
64
|
+
message: TransitionMessage,
|
|
65
|
+
});
|
|
66
|
+
/** Factory for the `Added` message, which carries a fully-constructed entry
|
|
67
|
+
* whose shape depends on the user-provided payload. */
|
|
68
|
+
export const makeAdded = (payloadSchema) => m('Added', { entry: makeEntry(payloadSchema) });
|
|
69
|
+
/** Factory for the union of all messages the toast component can produce. */
|
|
70
|
+
export const makeMessage = (payloadSchema) => S.Union(makeAdded(payloadSchema), Dismissed, DismissedAll, ElapsedDuration, HoveredEntry, LeftEntry, GotTransitionMessage);
|
|
71
|
+
export const DEFAULT_DURATION = Duration.seconds(4);
|