@vobs/ui 0.3.0 → 1.0.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.
Files changed (212) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +60 -0
  3. package/package.json +52 -110
  4. package/src/activity-rail.ts +125 -0
  5. package/src/alert.ts +65 -0
  6. package/src/assets/icons/alert-circle.svg +1 -0
  7. package/src/assets/icons/alert-triangle.svg +1 -0
  8. package/src/assets/icons/alert.d27e24.svg +1 -0
  9. package/src/assets/icons/alert.svg +1 -0
  10. package/src/assets/icons/apple.svg +1 -0
  11. package/src/assets/icons/arrow-down.svg +1 -0
  12. package/src/assets/icons/arrow-expand.svg +1 -0
  13. package/src/assets/icons/arrow-left.svg +1 -0
  14. package/src/assets/icons/arrow-minimize.svg +1 -0
  15. package/src/assets/icons/arrow-right-to-line.svg +1 -0
  16. package/src/assets/icons/arrow-right.svg +1 -0
  17. package/src/assets/icons/arrow-up-right.svg +1 -0
  18. package/src/assets/icons/arrow-up.0c0c0d.svg +1 -0
  19. package/src/assets/icons/arrow-up.svg +1 -0
  20. package/src/assets/icons/at.svg +1 -0
  21. package/src/assets/icons/atom.0c0c0d.svg +1 -0
  22. package/src/assets/icons/atom.svg +1 -0
  23. package/src/assets/icons/bar.svg +1 -0
  24. package/src/assets/icons/bell.svg +1 -0
  25. package/src/assets/icons/box.svg +1 -0
  26. package/src/assets/icons/bug.svg +1 -0
  27. package/src/assets/icons/calendar.svg +1 -0
  28. package/src/assets/icons/check-circle.33c192.svg +1 -0
  29. package/src/assets/icons/check-circle.svg +1 -0
  30. package/src/assets/icons/check.d1d3db.svg +1 -0
  31. package/src/assets/icons/check.svg +1 -0
  32. package/src/assets/icons/chevron-down.svg +1 -0
  33. package/src/assets/icons/chevron-right.svg +1 -0
  34. package/src/assets/icons/chevron-up.svg +1 -0
  35. package/src/assets/icons/circle.svg +1 -0
  36. package/src/assets/icons/clock.svg +1 -0
  37. package/src/assets/icons/cmd.svg +1 -0
  38. package/src/assets/icons/code.svg +1 -0
  39. package/src/assets/icons/columns.svg +1 -0
  40. package/src/assets/icons/copy.svg +1 -0
  41. package/src/assets/icons/cpu.svg +1 -0
  42. package/src/assets/icons/dashboard.0c0c0d.svg +1 -0
  43. package/src/assets/icons/dashboard.svg +1 -0
  44. package/src/assets/icons/dollar.svg +1 -0
  45. package/src/assets/icons/download.svg +1 -0
  46. package/src/assets/icons/edit.svg +1 -0
  47. package/src/assets/icons/extensions.svg +1 -0
  48. package/src/assets/icons/external.svg +1 -0
  49. package/src/assets/icons/eye.svg +1 -0
  50. package/src/assets/icons/file-text.svg +1 -0
  51. package/src/assets/icons/file.svg +1 -0
  52. package/src/assets/icons/files.svg +1 -0
  53. package/src/assets/icons/filter.svg +1 -0
  54. package/src/assets/icons/folder.svg +1 -0
  55. package/src/assets/icons/gear.svg +1 -0
  56. package/src/assets/icons/git.svg +1 -0
  57. package/src/assets/icons/github.svg +1 -0
  58. package/src/assets/icons/globe.svg +1 -0
  59. package/src/assets/icons/grid-2x2.svg +1 -0
  60. package/src/assets/icons/hash.svg +1 -0
  61. package/src/assets/icons/heart.svg +1 -0
  62. package/src/assets/icons/help.svg +1 -0
  63. package/src/assets/icons/home.svg +1 -0
  64. package/src/assets/icons/image.svg +1 -0
  65. package/src/assets/icons/info-circle.svg +1 -0
  66. package/src/assets/icons/info-square.svg +1 -0
  67. package/src/assets/icons/info.387bff.svg +1 -0
  68. package/src/assets/icons/info.svg +1 -0
  69. package/src/assets/icons/key.svg +1 -0
  70. package/src/assets/icons/layers.svg +1 -0
  71. package/src/assets/icons/layout.svg +1 -0
  72. package/src/assets/icons/link.svg +1 -0
  73. package/src/assets/icons/list.svg +1 -0
  74. package/src/assets/icons/lock.svg +1 -0
  75. package/src/assets/icons/log-out.svg +1 -0
  76. package/src/assets/icons/logo.svg +1 -0
  77. package/src/assets/icons/mail.svg +1 -0
  78. package/src/assets/icons/menu.svg +1 -0
  79. package/src/assets/icons/message-circle.svg +1 -0
  80. package/src/assets/icons/message-plus.svg +1 -0
  81. package/src/assets/icons/message-square.svg +1 -0
  82. package/src/assets/icons/mic.svg +1 -0
  83. package/src/assets/icons/minus.svg +1 -0
  84. package/src/assets/icons/moon.svg +1 -0
  85. package/src/assets/icons/more-h.svg +1 -0
  86. package/src/assets/icons/mouse.svg +1 -0
  87. package/src/assets/icons/palette.svg +1 -0
  88. package/src/assets/icons/panel-bottom.svg +1 -0
  89. package/src/assets/icons/pause.svg +1 -0
  90. package/src/assets/icons/play.svg +1 -0
  91. package/src/assets/icons/plug.svg +1 -0
  92. package/src/assets/icons/plus.0c0c0d.svg +1 -0
  93. package/src/assets/icons/plus.svg +1 -0
  94. package/src/assets/icons/refresh.svg +1 -0
  95. package/src/assets/icons/ruler.svg +1 -0
  96. package/src/assets/icons/scroll-text.svg +1 -0
  97. package/src/assets/icons/search-menu.svg +1 -0
  98. package/src/assets/icons/search.svg +1 -0
  99. package/src/assets/icons/send.0c0c0d.svg +1 -0
  100. package/src/assets/icons/send.svg +1 -0
  101. package/src/assets/icons/settings.0c0c0d.svg +1 -0
  102. package/src/assets/icons/settings.svg +1 -0
  103. package/src/assets/icons/shield.svg +1 -0
  104. package/src/assets/icons/sidebar-left.svg +1 -0
  105. package/src/assets/icons/sidebar-right.svg +1 -0
  106. package/src/assets/icons/sliders.svg +1 -0
  107. package/src/assets/icons/sparkles.32f08c.svg +1 -0
  108. package/src/assets/icons/sparkles.svg +1 -0
  109. package/src/assets/icons/square.svg +1 -0
  110. package/src/assets/icons/star.svg +1 -0
  111. package/src/assets/icons/sun.svg +1 -0
  112. package/src/assets/icons/terminal.svg +1 -0
  113. package/src/assets/icons/trash.svg +1 -0
  114. package/src/assets/icons/trending-down.svg +1 -0
  115. package/src/assets/icons/trending-up.svg +1 -0
  116. package/src/assets/icons/type.svg +1 -0
  117. package/src/assets/icons/upload.svg +1 -0
  118. package/src/assets/icons/user-circle.svg +1 -0
  119. package/src/assets/icons/user.svg +1 -0
  120. package/src/assets/icons/users.svg +1 -0
  121. package/src/assets/icons/wrench.svg +1 -0
  122. package/src/assets/icons/x-circle.svg +1 -0
  123. package/src/assets/icons/x.svg +1 -0
  124. package/src/assets/icons/zap.0c0c0d.svg +1 -0
  125. package/src/assets/icons/zap.svg +1 -0
  126. package/src/avatar.ts +64 -0
  127. package/src/button.ts +88 -0
  128. package/src/card.ts +59 -0
  129. package/src/chat-composer.ts +156 -0
  130. package/src/dialog.ts +127 -0
  131. package/src/drawer.ts +131 -0
  132. package/src/editor-tabs.ts +184 -0
  133. package/src/file-tree.ts +214 -0
  134. package/src/forms.ts +270 -0
  135. package/src/icon.ts +117 -0
  136. package/src/icons.js +165 -0
  137. package/src/index.test.ts +213 -0
  138. package/src/index.ts +94 -0
  139. package/src/kbd.ts +72 -0
  140. package/src/menu.ts +119 -0
  141. package/src/nav-list.ts +157 -0
  142. package/src/overlay.test.ts +66 -0
  143. package/src/overlay.ts +205 -0
  144. package/src/page-header.ts +97 -0
  145. package/src/pagination.ts +163 -0
  146. package/src/second-batch.test.ts +205 -0
  147. package/src/stat-card.ts +92 -0
  148. package/src/status-bar.ts +108 -0
  149. package/src/styles/base.css +240 -0
  150. package/src/styles/components.css +1234 -0
  151. package/{dist → src/styles}/styles.css +2 -0
  152. package/src/styles/toast.css +57 -0
  153. package/src/styles/tokens.css +438 -0
  154. package/src/styles/vui.css +47 -0
  155. package/src/table.ts +191 -0
  156. package/src/tabs.ts +100 -0
  157. package/src/tag.ts +33 -0
  158. package/src/third-batch.test.ts +137 -0
  159. package/src/toast.test.ts +55 -0
  160. package/src/toast.ts +79 -0
  161. package/src/types.ts +25 -0
  162. package/src/utils.ts +221 -0
  163. package/src/workbench-titlebar.ts +137 -0
  164. package/dist/app-shell-dom.d.ts +0 -30
  165. package/dist/app-shell-dom.js +0 -913
  166. package/dist/app-shell.d.ts +0 -235
  167. package/dist/app-shell.js +0 -415
  168. package/dist/base.css +0 -51
  169. package/dist/calendar-picker.d.ts +0 -45
  170. package/dist/calendar-picker.js +0 -217
  171. package/dist/calendar.d.ts +0 -95
  172. package/dist/calendar.js +0 -194
  173. package/dist/complex-inputs.d.ts +0 -300
  174. package/dist/complex-inputs.js +0 -866
  175. package/dist/components.css +0 -4756
  176. package/dist/data-display.d.ts +0 -1094
  177. package/dist/data-display.js +0 -2341
  178. package/dist/dialog.d.ts +0 -26
  179. package/dist/dialog.js +0 -94
  180. package/dist/feedback.d.ts +0 -88
  181. package/dist/feedback.js +0 -281
  182. package/dist/forms.d.ts +0 -378
  183. package/dist/forms.js +0 -1019
  184. package/dist/icons-config.d.ts +0 -25
  185. package/dist/icons-config.js +0 -14
  186. package/dist/icons.d.ts +0 -41
  187. package/dist/icons.js +0 -185
  188. package/dist/index.d.ts +0 -31
  189. package/dist/index.js +0 -40
  190. package/dist/locale/en-US.d.ts +0 -31
  191. package/dist/locale/en-US.js +0 -20
  192. package/dist/locale/zh-CN.d.ts +0 -31
  193. package/dist/locale/zh-CN.js +0 -20
  194. package/dist/navigation.d.ts +0 -609
  195. package/dist/navigation.js +0 -1707
  196. package/dist/overlay.d.ts +0 -308
  197. package/dist/overlay.js +0 -974
  198. package/dist/page-state.d.ts +0 -23
  199. package/dist/page-state.js +0 -96
  200. package/dist/primitives.d.ts +0 -268
  201. package/dist/primitives.js +0 -764
  202. package/dist/theme-data.d.ts +0 -394
  203. package/dist/theme-data.js +0 -417
  204. package/dist/theme.d.ts +0 -97
  205. package/dist/theme.js +0 -301
  206. package/dist/tokens.css +0 -570
  207. package/dist/tree.d.ts +0 -144
  208. package/dist/tree.js +0 -475
  209. package/dist/virtual-list.d.ts +0 -190
  210. package/dist/virtual-list.js +0 -538
  211. package/dist/workbench.d.ts +0 -136
  212. package/dist/workbench.js +0 -156
package/dist/dialog.d.ts DELETED
@@ -1,26 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/ui
4
- */
5
- import { type ComponentProps, type ComponentSlotContract } from '@vobs/runtime-dom';
6
- import { type OverlayCloseReason } from './overlay.js';
7
- export type DialogSize = 'lg' | 'md' | 'sm';
8
- export interface DialogProps {
9
- readonly open: boolean;
10
- readonly id: string;
11
- readonly size?: DialogSize;
12
- readonly modal?: boolean;
13
- readonly 'title-id'?: string;
14
- readonly 'description-id'?: string;
15
- readonly 'surface-class'?: string;
16
- readonly [key: string]: unknown;
17
- }
18
- export interface DialogEvents extends Record<string, (...args: never[]) => unknown> {
19
- readonly close: (reason: OverlayCloseReason) => void;
20
- }
21
- export interface DialogScope {
22
- readonly props: ComponentProps<DialogProps>;
23
- readonly emit: <Name extends keyof DialogEvents & string>(name: Name, ...args: Parameters<DialogEvents[Name]>) => void;
24
- }
25
- export type DialogSlots = Readonly<ComponentSlotContract>;
26
- export declare const Dialog: import("@vobs/runtime-core").ComponentDefinition<DialogProps, DialogEvents, DialogScope, Readonly<Readonly<Record<string, Readonly<Record<string, unknown>>>>>>;
package/dist/dialog.js DELETED
@@ -1,94 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/ui
4
- */
5
- import { effect } from '@vobs/reactivity';
6
- import { COMPONENT_SLOTS, createCompiledTemplate, defineComponent, } from '@vobs/runtime-dom';
7
- import { createOverlayStack } from './overlay.js';
8
- export const Dialog = defineComponent({
9
- template: createCompiledTemplate({
10
- templateId: 'k-dialog',
11
- sourceId: '@vobs/ui/dialog',
12
- rootTag: 'div',
13
- mount(owner, scope, environment) {
14
- return mountDialog(owner, scope, environment);
15
- },
16
- }),
17
- props: ['open', 'id', 'size', 'modal', 'title-id', 'description-id', 'surface-class'],
18
- emits: ['close'],
19
- [COMPONENT_SLOTS]: { default: {} },
20
- setup(context) {
21
- return {
22
- props: context.props,
23
- emit: (name, ...args) => context.emit(name, ...args),
24
- };
25
- },
26
- });
27
- function mountDialog(owner, scope, environment) {
28
- const root = document.createElement('div');
29
- root.className = 'kui-overlay-root';
30
- root.setAttribute('data-backdrop', 'true');
31
- root.setAttribute('role', 'presentation');
32
- const surface = document.createElement('section');
33
- surface.className = 'kui-dialog';
34
- surface.setAttribute('role', 'dialog');
35
- surface.setAttribute('aria-modal', 'true');
36
- root.append(surface);
37
- environment.slots?.default?.(owner, surface);
38
- const stack = createOverlayStack({ document });
39
- let handle;
40
- let wasOpen = false;
41
- const stop = effect(() => {
42
- const props = scope.props;
43
- const open = props.open.value === true;
44
- const id = readString(props.id.value, 'dialog');
45
- const size = readSize(props.size?.value);
46
- const modal = props.modal?.value !== false;
47
- root.hidden = !open;
48
- root.setAttribute('data-state', open ? 'open' : 'closed');
49
- surface.id = id;
50
- surface.setAttribute('data-size', size);
51
- surface.setAttribute('aria-modal', String(modal));
52
- setOptionalAttribute(surface, 'aria-labelledby', props['title-id']?.value);
53
- setOptionalAttribute(surface, 'aria-describedby', props['description-id']?.value);
54
- const surfaceClass = readString(props['surface-class']?.value, '');
55
- surface.className = `kui-dialog${surfaceClass === '' ? '' : ` ${surfaceClass}`}`;
56
- if (open === wasOpen)
57
- return;
58
- wasOpen = open;
59
- if (open) {
60
- handle = stack.open({
61
- id,
62
- kind: 'dialog',
63
- modal,
64
- element: surface,
65
- managedElement: false,
66
- closeOnOutside: true,
67
- onClose: (reason) => scope.emit('close', reason),
68
- });
69
- }
70
- else {
71
- handle?.destroy();
72
- handle = undefined;
73
- }
74
- }, { scheduler: environment.scheduler, flush: 'post' });
75
- owner.own(stop);
76
- owner.own(() => {
77
- handle?.destroy();
78
- stack.destroy();
79
- });
80
- return { root, refs: {} };
81
- }
82
- function readString(value, fallback) {
83
- return typeof value === 'string' && value.trim() !== '' ? value : fallback;
84
- }
85
- function readSize(value) {
86
- return value === 'sm' || value === 'lg' ? value : 'md';
87
- }
88
- function setOptionalAttribute(element, name, value) {
89
- const normalized = typeof value === 'string' ? value.trim() : '';
90
- if (normalized === '')
91
- element.removeAttribute(name);
92
- else
93
- element.setAttribute(name, normalized);
94
- }
@@ -1,88 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/ui
4
- */
5
- import { type UiDomPlan } from './primitives.js';
6
- export type FeedbackStatus = 'error' | 'info' | 'success' | 'warning';
7
- export type ToastPlacement = 'bottom-end' | 'top-center' | 'top-end';
8
- export type FeedbackActionTone = 'default' | 'primary';
9
- export type FeedbackSurfaceKind = 'alert' | 'message' | 'notification' | 'toast';
10
- export interface AlertPlanOptions {
11
- readonly id?: string;
12
- readonly status?: FeedbackStatus;
13
- readonly titleId?: string;
14
- readonly descriptionId?: string;
15
- }
16
- export interface MessagePlanOptions {
17
- readonly id?: string;
18
- readonly status?: FeedbackStatus;
19
- }
20
- export interface FeedbackAction {
21
- readonly id: string;
22
- readonly label: string;
23
- readonly tone?: FeedbackActionTone;
24
- readonly disabled?: boolean;
25
- }
26
- export interface FeedbackSurfacePlanOptions {
27
- readonly id?: string;
28
- readonly status?: FeedbackStatus;
29
- readonly titleId?: string;
30
- readonly descriptionId?: string;
31
- readonly closeLabel?: string;
32
- readonly action?: FeedbackAction;
33
- readonly icon?: boolean;
34
- readonly loading?: boolean;
35
- }
36
- export interface FeedbackSurfacePlans {
37
- readonly root: UiDomPlan<'div'>;
38
- readonly icon?: UiDomPlan<'span'>;
39
- readonly content: UiDomPlan<'div'>;
40
- readonly title?: UiDomPlan<'strong'>;
41
- readonly description?: UiDomPlan<'p'>;
42
- readonly actionButton?: UiDomPlan<'button'>;
43
- readonly closeButton?: UiDomPlan<'button'>;
44
- readonly loadingIndicator?: UiDomPlan<'span'>;
45
- }
46
- export interface ToastQueueOptions {
47
- readonly timeoutMs?: number;
48
- readonly timers?: ToastTimers;
49
- }
50
- export interface ToastTimers {
51
- setTimeout(callback: () => void, delayMs: number): unknown;
52
- clearTimeout(timer: unknown): void;
53
- }
54
- export interface ToastInput {
55
- readonly id?: string;
56
- readonly status?: FeedbackStatus;
57
- readonly title: string;
58
- readonly description?: string;
59
- readonly timeoutMs?: number;
60
- }
61
- export interface ToastItem extends Required<Pick<ToastInput, 'id' | 'status' | 'title'>> {
62
- readonly description?: string;
63
- readonly remainingMs: number;
64
- readonly paused: boolean;
65
- }
66
- export interface ToastQueue {
67
- readonly items: readonly ToastItem[];
68
- push(input: ToastInput): ToastItem;
69
- dismiss(id: string): void;
70
- pause(id: string): void;
71
- resume(id: string): void;
72
- clear(): void;
73
- destroy(): void;
74
- }
75
- export interface ToastRegionPlanOptions {
76
- readonly placement?: ToastPlacement;
77
- readonly label?: string;
78
- }
79
- export declare function createAlertPlan(options?: AlertPlanOptions): UiDomPlan<'div'>;
80
- export declare function createAlertPlans(options?: FeedbackSurfacePlanOptions): FeedbackSurfacePlans;
81
- export declare function createMessagePlan(options?: MessagePlanOptions): UiDomPlan<'div'>;
82
- export declare function createMessagePlans(options?: FeedbackSurfacePlanOptions): FeedbackSurfacePlans;
83
- export declare function createToastRegionPlan(options?: ToastRegionPlanOptions): UiDomPlan<'div'>;
84
- export declare function createToastPlan(item: ToastItem): UiDomPlan<'div'>;
85
- export declare function createToastItemPlans(item: ToastItem, options?: Omit<FeedbackSurfacePlanOptions, 'id' | 'status'>): FeedbackSurfacePlans;
86
- export declare function createNotificationRegionPlan(options?: ToastRegionPlanOptions): UiDomPlan<'div'>;
87
- export declare function createNotificationPlans(item: ToastItem, options?: Omit<FeedbackSurfacePlanOptions, 'id' | 'status'>): FeedbackSurfacePlans;
88
- export declare function createToastQueue(options?: ToastQueueOptions): ToastQueue;
package/dist/feedback.js DELETED
@@ -1,281 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/ui
4
- */
5
- import { classNames, createButtonPrimitive, createSpinPrimitive, createUiDomPlan, } from './primitives.js';
6
- export function createAlertPlan(options = {}) {
7
- const status = options.status ?? 'info';
8
- return createUiDomPlan('div', 'alert', {
9
- state: status,
10
- attrs: {
11
- id: options.id,
12
- role: status === 'error' || status === 'warning' ? 'alert' : 'status',
13
- 'aria-labelledby': options.titleId,
14
- 'aria-describedby': options.descriptionId,
15
- 'data-status': status,
16
- },
17
- });
18
- }
19
- export function createAlertPlans(options = {}) {
20
- return createFeedbackSurfacePlans('alert', options);
21
- }
22
- export function createMessagePlan(options = {}) {
23
- const status = options.status ?? 'info';
24
- return createUiDomPlan('div', 'message', {
25
- state: status,
26
- attrs: {
27
- id: options.id,
28
- role: status === 'error' ? 'alert' : 'status',
29
- 'data-status': status,
30
- },
31
- });
32
- }
33
- export function createMessagePlans(options = {}) {
34
- return createFeedbackSurfacePlans('message', options);
35
- }
36
- export function createToastRegionPlan(options = {}) {
37
- const placement = options.placement ?? 'top-end';
38
- return createUiDomPlan('div', 'toast-region', {
39
- state: 'idle',
40
- attrs: {
41
- role: 'region',
42
- 'aria-live': 'polite',
43
- 'aria-label': options.label ?? 'Notifications',
44
- 'data-placement': placement,
45
- },
46
- });
47
- }
48
- export function createToastPlan(item) {
49
- return createUiDomPlan('div', 'toast', {
50
- state: item.paused ? 'paused' : 'open',
51
- attrs: {
52
- id: item.id,
53
- role: item.status === 'error' ? 'alert' : 'status',
54
- 'data-status': item.status,
55
- 'data-paused': item.paused ? '' : undefined,
56
- },
57
- });
58
- }
59
- export function createToastItemPlans(item, options = {}) {
60
- return createFeedbackSurfacePlans('toast', {
61
- ...options,
62
- id: item.id,
63
- status: item.status,
64
- titleId: `${item.id}-title`,
65
- ...(item.description === undefined ? {} : { descriptionId: `${item.id}-description` }),
66
- });
67
- }
68
- export function createNotificationRegionPlan(options = {}) {
69
- const region = createToastRegionPlan(options);
70
- return {
71
- ...region,
72
- className: `${region.className} kui-notification-region`,
73
- attrs: {
74
- ...region.attrs,
75
- 'data-region-kind': 'notification',
76
- },
77
- };
78
- }
79
- export function createNotificationPlans(item, options = {}) {
80
- const plans = createFeedbackSurfacePlans('notification', {
81
- ...options,
82
- id: item.id,
83
- status: item.status,
84
- titleId: `${item.id}-title`,
85
- ...(item.description === undefined ? {} : { descriptionId: `${item.id}-description` }),
86
- });
87
- return {
88
- ...plans,
89
- root: {
90
- ...plans.root,
91
- attrs: {
92
- ...plans.root.attrs,
93
- 'data-paused': item.paused ? '' : undefined,
94
- 'data-remaining-ms': item.remainingMs,
95
- },
96
- },
97
- };
98
- }
99
- export function createToastQueue(options = {}) {
100
- const timeoutMs = options.timeoutMs ?? 5000;
101
- const timers = options.timers ?? globalTimers;
102
- const entries = [];
103
- let nextId = 1;
104
- const queue = {
105
- get items() {
106
- return entries.map((entry) => readToast(entry));
107
- },
108
- push(input) {
109
- const entry = {
110
- id: input.id ?? `toast-${nextId++}`,
111
- status: input.status ?? 'info',
112
- title: input.title,
113
- ...(input.description === undefined ? {} : { description: input.description }),
114
- remainingMs: input.timeoutMs ?? timeoutMs,
115
- startedAt: Date.now(),
116
- paused: false,
117
- };
118
- entries.push(entry);
119
- schedule(entry);
120
- return readToast(entry);
121
- },
122
- dismiss(id) {
123
- const entry = findEntry(id);
124
- if (entry === undefined)
125
- return;
126
- clear(entry);
127
- entries.splice(entries.indexOf(entry), 1);
128
- },
129
- pause(id) {
130
- const entry = findEntry(id);
131
- if (entry === undefined || entry.paused)
132
- return;
133
- entry.remainingMs = Math.max(0, entry.remainingMs - (Date.now() - entry.startedAt));
134
- entry.paused = true;
135
- clear(entry);
136
- },
137
- resume(id) {
138
- const entry = findEntry(id);
139
- if (entry === undefined || !entry.paused)
140
- return;
141
- entry.paused = false;
142
- schedule(entry);
143
- },
144
- clear() {
145
- for (const entry of [...entries])
146
- queue.dismiss(entry.id);
147
- },
148
- destroy() {
149
- queue.clear();
150
- },
151
- };
152
- function findEntry(id) {
153
- return entries.find((entry) => entry.id === id);
154
- }
155
- function schedule(entry) {
156
- clear(entry);
157
- entry.startedAt = Date.now();
158
- entry.timer = timers.setTimeout(() => queue.dismiss(entry.id), entry.remainingMs);
159
- }
160
- function clear(entry) {
161
- if (entry.timer === undefined)
162
- return;
163
- timers.clearTimeout(entry.timer);
164
- delete entry.timer;
165
- }
166
- return queue;
167
- }
168
- function readToast(entry) {
169
- return {
170
- id: entry.id,
171
- status: entry.status,
172
- title: entry.title,
173
- ...(entry.description === undefined ? {} : { description: entry.description }),
174
- remainingMs: entry.remainingMs,
175
- paused: entry.paused,
176
- };
177
- }
178
- function createFeedbackSurfacePlans(kind, options) {
179
- const status = options.status ?? 'info';
180
- const root = createFeedbackRootPlan(kind, options);
181
- return {
182
- root,
183
- ...(options.icon === false
184
- ? {}
185
- : {
186
- icon: createUiDomPlan('span', `${kind}-icon`, {
187
- attrs: {
188
- 'aria-hidden': 'true',
189
- 'data-status': status,
190
- },
191
- }),
192
- }),
193
- content: createUiDomPlan('div', `${kind}-content`),
194
- ...(options.titleId === undefined
195
- ? {}
196
- : {
197
- title: createUiDomPlan('strong', `${kind}-title`, {
198
- attrs: { id: options.titleId },
199
- }),
200
- }),
201
- ...(options.descriptionId === undefined
202
- ? {}
203
- : {
204
- description: createUiDomPlan('p', `${kind}-description`, {
205
- attrs: { id: options.descriptionId },
206
- }),
207
- }),
208
- ...(options.action === undefined
209
- ? {}
210
- : {
211
- actionButton: createButtonPrimitive({
212
- label: options.action.label,
213
- variant: options.action.tone === 'primary' ? 'solid' : 'soft',
214
- size: 'sm',
215
- disabled: options.action.disabled === true,
216
- className: classNames(`kui-${kind}-action`, options.action.tone === undefined
217
- ? undefined
218
- : `kui-${kind}-action--${options.action.tone}`),
219
- attrs: {
220
- id: `${options.id ?? kind}-${options.action.id}-action`,
221
- 'data-action-id': options.action.id,
222
- 'data-tone': options.action.tone ?? 'default',
223
- },
224
- }),
225
- }),
226
- ...(options.closeLabel === undefined
227
- ? {}
228
- : {
229
- closeButton: createButtonPrimitive({
230
- label: options.closeLabel,
231
- variant: 'ghost',
232
- size: 'sm',
233
- iconOnly: true,
234
- className: `kui-${kind}-close`,
235
- attrs: {
236
- id: `${options.id ?? kind}-close`,
237
- 'data-feedback-close': '',
238
- },
239
- }),
240
- }),
241
- ...(options.loading === true
242
- ? {
243
- loadingIndicator: createSpinPrimitive({
244
- label: 'Loading',
245
- className: `kui-${kind}-loading`,
246
- }),
247
- }
248
- : {}),
249
- };
250
- }
251
- function createFeedbackRootPlan(kind, options) {
252
- const status = options.status ?? 'info';
253
- return createUiDomPlan('div', kind, {
254
- state: options.loading === true ? 'loading' : status,
255
- loading: options.loading === true,
256
- attrs: {
257
- id: options.id,
258
- role: feedbackRole(kind, status),
259
- 'aria-labelledby': options.titleId,
260
- 'aria-describedby': options.descriptionId,
261
- 'data-status': status,
262
- 'data-dismissible': options.closeLabel === undefined ? undefined : '',
263
- 'data-actionable': options.action === undefined ? undefined : '',
264
- },
265
- });
266
- }
267
- function feedbackRole(kind, status) {
268
- if (status === 'error')
269
- return 'alert';
270
- if (kind === 'alert' && status === 'warning')
271
- return 'alert';
272
- return 'status';
273
- }
274
- const globalTimers = {
275
- setTimeout(callback, delayMs) {
276
- return setTimeout(callback, delayMs);
277
- },
278
- clearTimeout(timer) {
279
- clearTimeout(timer);
280
- },
281
- };