@jrgermain/stylesheet 0.19.0 → 0.19.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
+ export * from "./lib/popup";
1
2
  export * from "./lib/tokens";
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
+ export * from "./lib/popup";
1
2
  export * from "./lib/tokens";
@@ -0,0 +1,66 @@
1
+ export type PopupOptions = {
2
+ /**
3
+ * The title of the popup.
4
+ *
5
+ * Displayed at the top of the modal and used as its name for screen readers.
6
+ *
7
+ * If omitted or set to an empty string, the dialog will use the default title of "Alert".
8
+ *
9
+ * @default "Alert"
10
+ */
11
+ title?: string;
12
+ /**
13
+ * The content to display within the popup.
14
+ *
15
+ * @default "" // No content
16
+ */
17
+ message?: string | Element | (string | Element)[];
18
+ /**
19
+ * The size of Modal component to display.
20
+ *
21
+ * This controls the width of the Modal.
22
+ *
23
+ * @default "auto"
24
+ */
25
+ size?: "auto" | "small" | "medium" | "large";
26
+ /**
27
+ * Whether the primary action (represented by the 'OK' button) is destructive.
28
+ *
29
+ * Examples of destructive actions include deleting data or making an irreversible change.
30
+ * In this case, we're likely using the popup to get the user's confirmation before
31
+ * proceeding with a destructive action.
32
+ *
33
+ * If true, the OK button will be displayed in red.
34
+ *
35
+ * @default false
36
+ */
37
+ isDestructive?: boolean;
38
+ /**
39
+ * The label for the primary action button.
40
+ *
41
+ * If omitted or set to an empty string, the primary button will use the default label of "OK".
42
+ *
43
+ * @default "OK"
44
+ */
45
+ primaryLabel?: string;
46
+ /**
47
+ * The label for the secondary action button.
48
+ *
49
+ * If omitted or set to an empty string, no secondary action button will be displayed.
50
+ *
51
+ * @default "" // No secondary button
52
+ */
53
+ secondaryLabel?: string;
54
+ };
55
+ /**
56
+ * Display a Modal and handle user interaction with Promises.
57
+ *
58
+ * Similar to the native `window.alert()` and `window.confirm()` but async, configurable, and
59
+ * consistent across browsers.
60
+ *
61
+ * @returns a Promise that resolves once the modal is dismissed. The resolved value is:
62
+ * - `true` if the user clicked the primary button
63
+ * - `false` if the user clicked the secondary button
64
+ * - `null` if the user dismissed the modal by other means (e.g., pressing the Escape key)
65
+ */
66
+ export declare const showPopup: ({ title, message, size, isDestructive, primaryLabel, secondaryLabel, }: PopupOptions) => Promise<boolean | null>;
@@ -0,0 +1,104 @@
1
+ const toArray = (item) => {
2
+ if (item == null)
3
+ return [];
4
+ return Array.isArray(item) ? item : [item];
5
+ };
6
+ const toElement = (item) => {
7
+ if (typeof item === "string") {
8
+ const p = document.createElement("p");
9
+ p.className = "paragraph";
10
+ p.textContent = item;
11
+ return p;
12
+ }
13
+ return item;
14
+ };
15
+ /**
16
+ * Display a Modal and handle user interaction with Promises.
17
+ *
18
+ * Similar to the native `window.alert()` and `window.confirm()` but async, configurable, and
19
+ * consistent across browsers.
20
+ *
21
+ * @returns a Promise that resolves once the modal is dismissed. The resolved value is:
22
+ * - `true` if the user clicked the primary button
23
+ * - `false` if the user clicked the secondary button
24
+ * - `null` if the user dismissed the modal by other means (e.g., pressing the Escape key)
25
+ */
26
+ export const showPopup = ({ title = "Alert", message = "", size = "auto", isDestructive = false, primaryLabel = "OK", secondaryLabel = "", }) => {
27
+ return new Promise((resolve) => {
28
+ const id = Math.random().toString(36).slice(-8);
29
+ const modalId = `modal-${id}`;
30
+ const titleId = `modal-${id}-title`;
31
+ // Modal Root
32
+ const dialog = document.createElement("dialog");
33
+ dialog.id = modalId;
34
+ dialog.className = "modal";
35
+ dialog.setAttribute("aria-labelledby", titleId);
36
+ if (size !== "auto") {
37
+ dialog.classList.add(size);
38
+ }
39
+ // Modal Header
40
+ const header = document.createElement("header");
41
+ header.className = "modal-header";
42
+ const h1 = document.createElement("h1");
43
+ h1.id = titleId;
44
+ h1.textContent = title || "Alert"; // Fallback if title is empty
45
+ header.appendChild(h1);
46
+ dialog.appendChild(header);
47
+ // Modal Body
48
+ const body = document.createElement("div");
49
+ body.className = "modal-body";
50
+ const content = toArray(message);
51
+ for (const item of content) {
52
+ if (!item)
53
+ continue;
54
+ const element = toElement(item);
55
+ body.appendChild(element);
56
+ }
57
+ dialog.appendChild(body);
58
+ // Modal Footer
59
+ const footer = document.createElement("div");
60
+ footer.className = "modal-footer";
61
+ // OK Button
62
+ const primaryButton = document.createElement("button");
63
+ primaryButton.className = "button primary";
64
+ if (isDestructive) {
65
+ primaryButton.classList.add("red");
66
+ }
67
+ primaryButton.textContent = primaryLabel || "OK"; // Fallback if primaryLabel is empty
68
+ primaryButton.addEventListener("click", () => {
69
+ dialog.requestClose("primary");
70
+ });
71
+ footer.appendChild(primaryButton);
72
+ // Cancel Button
73
+ if (secondaryLabel) {
74
+ const secondaryButton = document.createElement("button");
75
+ secondaryButton.className = "button";
76
+ secondaryButton.textContent = secondaryLabel;
77
+ secondaryButton.addEventListener("click", () => {
78
+ dialog.requestClose("secondary");
79
+ });
80
+ footer.appendChild(secondaryButton);
81
+ }
82
+ dialog.appendChild(footer);
83
+ // Handle close event
84
+ dialog.addEventListener("close", () => {
85
+ // Remove from DOM after close animation finishes
86
+ setTimeout(() => {
87
+ dialog.remove();
88
+ }, 1000);
89
+ switch (dialog.returnValue) {
90
+ case "primary":
91
+ resolve(true);
92
+ break;
93
+ case "secondary":
94
+ resolve(false);
95
+ break;
96
+ default:
97
+ resolve(null);
98
+ }
99
+ });
100
+ // Display the popup
101
+ document.body.appendChild(dialog);
102
+ dialog.showModal();
103
+ });
104
+ };