@hadoku/task-ui-components 0.0.0-stage → 4.20.3
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/LICENSE +21 -0
- package/README.md +917 -2
- package/dist/app-header.css +288 -0
- package/dist/bento.css +143 -0
- package/dist/button.css +227 -0
- package/dist/components/AppHeader.d.ts +61 -0
- package/dist/components/AppHeader.d.ts.map +1 -0
- package/dist/components/AppHeader.js +23 -0
- package/dist/components/AppHeader.js.map +1 -0
- package/dist/components/BentoCard.d.ts +23 -0
- package/dist/components/BentoCard.d.ts.map +1 -0
- package/dist/components/BentoCard.js +49 -0
- package/dist/components/BentoCard.js.map +1 -0
- package/dist/components/BentoGrid.d.ts +24 -0
- package/dist/components/BentoGrid.d.ts.map +1 -0
- package/dist/components/BentoGrid.js +22 -0
- package/dist/components/BentoGrid.js.map +1 -0
- package/dist/components/Button.d.ts +28 -0
- package/dist/components/Button.d.ts.map +1 -0
- package/dist/components/Button.js +51 -0
- package/dist/components/Button.js.map +1 -0
- package/dist/components/ConnectedSettings.d.ts +53 -0
- package/dist/components/ConnectedSettings.d.ts.map +1 -0
- package/dist/components/ConnectedSettings.js +302 -0
- package/dist/components/ConnectedSettings.js.map +1 -0
- package/dist/components/ConnectedThemePicker.d.ts +52 -0
- package/dist/components/ConnectedThemePicker.d.ts.map +1 -0
- package/dist/components/ConnectedThemePicker.js +32 -0
- package/dist/components/ConnectedThemePicker.js.map +1 -0
- package/dist/components/ContextMenu.d.ts +22 -0
- package/dist/components/ContextMenu.d.ts.map +1 -0
- package/dist/components/ContextMenu.js +23 -0
- package/dist/components/ContextMenu.js.map +1 -0
- package/dist/components/HadokuThemePicker.d.ts +27 -0
- package/dist/components/HadokuThemePicker.d.ts.map +1 -0
- package/dist/components/HadokuThemePicker.js +19 -0
- package/dist/components/HadokuThemePicker.js.map +1 -0
- package/dist/components/LoadingSkeleton.d.ts +14 -0
- package/dist/components/LoadingSkeleton.d.ts.map +1 -0
- package/dist/components/LoadingSkeleton.js +62 -0
- package/dist/components/LoadingSkeleton.js.map +1 -0
- package/dist/components/Modal.d.ts +39 -0
- package/dist/components/Modal.d.ts.map +1 -0
- package/dist/components/Modal.js +106 -0
- package/dist/components/Modal.js.map +1 -0
- package/dist/components/NumberInput.d.ts +26 -0
- package/dist/components/NumberInput.d.ts.map +1 -0
- package/dist/components/NumberInput.js +131 -0
- package/dist/components/NumberInput.js.map +1 -0
- package/dist/components/Select.d.ts +52 -0
- package/dist/components/Select.d.ts.map +1 -0
- package/dist/components/Select.js +281 -0
- package/dist/components/Select.js.map +1 -0
- package/dist/components/SettingsModal.d.ts +69 -0
- package/dist/components/SettingsModal.d.ts.map +1 -0
- package/dist/components/SettingsModal.js +141 -0
- package/dist/components/SettingsModal.js.map +1 -0
- package/dist/components/ThemeIcons.d.ts +26 -0
- package/dist/components/ThemeIcons.d.ts.map +1 -0
- package/dist/components/ThemeIcons.js +74 -0
- package/dist/components/ThemeIcons.js.map +1 -0
- package/dist/components/ThemePicker.d.ts +28 -0
- package/dist/components/ThemePicker.d.ts.map +1 -0
- package/dist/components/ThemePicker.js +101 -0
- package/dist/components/ThemePicker.js.map +1 -0
- package/dist/components/Toast.d.ts +13 -0
- package/dist/components/Toast.d.ts.map +1 -0
- package/dist/components/Toast.js +70 -0
- package/dist/components/Toast.js.map +1 -0
- package/dist/components/Toaster.d.ts +19 -0
- package/dist/components/Toaster.d.ts.map +1 -0
- package/dist/components/Toaster.js +19 -0
- package/dist/components/Toaster.js.map +1 -0
- package/dist/components/Tooltip.d.ts +49 -0
- package/dist/components/Tooltip.d.ts.map +1 -0
- package/dist/components/Tooltip.js +143 -0
- package/dist/components/Tooltip.js.map +1 -0
- package/dist/context-menu.css +11 -0
- package/dist/controls.css +137 -0
- package/dist/hooks/useReducedMotion.d.ts +7 -0
- package/dist/hooks/useReducedMotion.d.ts.map +1 -0
- package/dist/hooks/useReducedMotion.js +25 -0
- package/dist/hooks/useReducedMotion.js.map +1 -0
- package/dist/hooks/useToast.d.ts +18 -0
- package/dist/hooks/useToast.d.ts.map +1 -0
- package/dist/hooks/useToast.js +28 -0
- package/dist/hooks/useToast.js.map +1 -0
- package/dist/icon-btn.css +64 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/menuPlacement.d.ts +16 -0
- package/dist/lib/menuPlacement.d.ts.map +1 -0
- package/dist/lib/menuPlacement.js +19 -0
- package/dist/lib/menuPlacement.js.map +1 -0
- package/dist/lib/selectMenus.d.ts +30 -0
- package/dist/lib/selectMenus.d.ts.map +1 -0
- package/dist/lib/selectMenus.js +236 -0
- package/dist/lib/selectMenus.js.map +1 -0
- package/dist/lib/settingsClient.d.ts +120 -0
- package/dist/lib/settingsClient.d.ts.map +1 -0
- package/dist/lib/settingsClient.js +140 -0
- package/dist/lib/settingsClient.js.map +1 -0
- package/dist/lib/themeScope.d.ts +19 -0
- package/dist/lib/themeScope.d.ts.map +1 -0
- package/dist/lib/themeScope.js +10 -0
- package/dist/lib/themeScope.js.map +1 -0
- package/dist/lib/titleTooltips.d.ts +38 -0
- package/dist/lib/titleTooltips.d.ts.map +1 -0
- package/dist/lib/titleTooltips.js +166 -0
- package/dist/lib/titleTooltips.js.map +1 -0
- package/dist/lib/tooltipPlacement.d.ts +14 -0
- package/dist/lib/tooltipPlacement.d.ts.map +1 -0
- package/dist/lib/tooltipPlacement.js +34 -0
- package/dist/lib/tooltipPlacement.js.map +1 -0
- package/dist/modal.css +129 -0
- package/dist/number-input.css +131 -0
- package/dist/scrollbar.css +165 -0
- package/dist/select.css +251 -0
- package/dist/styles.css +1866 -0
- package/dist/task-ui-components.css +1866 -0
- package/dist/theme-picker.css +219 -0
- package/dist/toaster.css +159 -0
- package/dist/tooltip.css +103 -0
- package/dist/types/index.d.ts +37 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +60 -4
- package/src/app-header.css +288 -0
- package/src/bento.css +143 -0
- package/src/button.css +227 -0
- package/src/components/AppHeader.tsx +87 -0
- package/src/components/BentoCard.tsx +72 -0
- package/src/components/BentoGrid.tsx +48 -0
- package/src/components/Button.tsx +81 -0
- package/src/components/ConnectedSettings.tsx +465 -0
- package/src/components/ConnectedThemePicker.tsx +79 -0
- package/src/components/ContextMenu.tsx +48 -0
- package/src/components/HadokuThemePicker.tsx +39 -0
- package/src/components/LoadingSkeleton.tsx +84 -0
- package/src/components/Modal.tsx +171 -0
- package/src/components/NumberInput.tsx +161 -0
- package/src/components/Select.tsx +359 -0
- package/src/components/SettingsModal.tsx +235 -0
- package/src/components/ThemeIcons.tsx +127 -0
- package/src/components/ThemePicker.tsx +149 -0
- package/src/components/Toast.tsx +92 -0
- package/src/components/Toaster.tsx +43 -0
- package/src/components/Tooltip.tsx +212 -0
- package/src/context-menu.css +11 -0
- package/src/controls.css +137 -0
- package/src/hooks/useReducedMotion.ts +36 -0
- package/src/hooks/useToast.ts +57 -0
- package/src/icon-btn.css +64 -0
- package/src/index.ts +140 -0
- package/src/lib/menuPlacement.ts +31 -0
- package/src/lib/selectMenus.ts +303 -0
- package/src/lib/settingsClient.ts +377 -0
- package/src/lib/themeScope.ts +23 -0
- package/src/lib/titleTooltips.ts +236 -0
- package/src/lib/tooltipPlacement.ts +59 -0
- package/src/modal.css +129 -0
- package/src/number-input.css +131 -0
- package/src/scrollbar.css +165 -0
- package/src/select.css +251 -0
- package/src/theme-picker.css +219 -0
- package/src/toaster.css +159 -0
- package/src/tooltip.css +103 -0
- package/src/types/index.ts +43 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Modal } from "./Modal.js";
|
|
3
|
+
import { Select } from "./Select.js";
|
|
4
|
+
function SettingsModal({
|
|
5
|
+
isOpen,
|
|
6
|
+
title = "Settings",
|
|
7
|
+
sections,
|
|
8
|
+
onClose,
|
|
9
|
+
className = "",
|
|
10
|
+
showCloseButton = true
|
|
11
|
+
}) {
|
|
12
|
+
const renderField = (field) => {
|
|
13
|
+
switch (field.type) {
|
|
14
|
+
case "toggle":
|
|
15
|
+
return /* @__PURE__ */ jsxs("div", { className: "settings-field", children: [
|
|
16
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-field-header", children: [
|
|
17
|
+
/* @__PURE__ */ jsx("label", { className: "settings-field-label", htmlFor: field.id, children: field.label }),
|
|
18
|
+
/* @__PURE__ */ jsx(
|
|
19
|
+
"input",
|
|
20
|
+
{
|
|
21
|
+
type: "checkbox",
|
|
22
|
+
id: field.id,
|
|
23
|
+
className: "settings-toggle",
|
|
24
|
+
checked: field.value,
|
|
25
|
+
onChange: (e) => field.onChange(e.target.checked),
|
|
26
|
+
disabled: field.disabled
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
] }),
|
|
30
|
+
field.description && /* @__PURE__ */ jsx("p", { className: "settings-field-description", children: field.description })
|
|
31
|
+
] }, field.id);
|
|
32
|
+
case "text":
|
|
33
|
+
return /* @__PURE__ */ jsxs("div", { className: "settings-field", children: [
|
|
34
|
+
/* @__PURE__ */ jsx("label", { className: "settings-field-label", htmlFor: field.id, children: field.label }),
|
|
35
|
+
field.description && /* @__PURE__ */ jsx("p", { className: "settings-field-description", children: field.description }),
|
|
36
|
+
/* @__PURE__ */ jsx(
|
|
37
|
+
"input",
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
id: field.id,
|
|
41
|
+
className: "settings-text-input",
|
|
42
|
+
value: field.value,
|
|
43
|
+
onChange: (e) => field.onChange(e.target.value),
|
|
44
|
+
placeholder: field.placeholder,
|
|
45
|
+
disabled: field.disabled
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
] }, field.id);
|
|
49
|
+
case "password":
|
|
50
|
+
return /* @__PURE__ */ jsxs("div", { className: "settings-field", children: [
|
|
51
|
+
/* @__PURE__ */ jsx("label", { className: "settings-field-label", htmlFor: field.id, children: field.label }),
|
|
52
|
+
field.description && /* @__PURE__ */ jsx("p", { className: "settings-field-description", children: field.description }),
|
|
53
|
+
/* @__PURE__ */ jsxs("div", { className: "settings-field-input-group", children: [
|
|
54
|
+
/* @__PURE__ */ jsx(
|
|
55
|
+
"input",
|
|
56
|
+
{
|
|
57
|
+
type: "password",
|
|
58
|
+
id: field.id,
|
|
59
|
+
name: field.autoComplete || field.id,
|
|
60
|
+
autoComplete: field.autoComplete || "off",
|
|
61
|
+
className: "settings-text-input",
|
|
62
|
+
value: field.value,
|
|
63
|
+
onChange: (e) => field.onChange(e.target.value),
|
|
64
|
+
placeholder: field.placeholder,
|
|
65
|
+
disabled: field.disabled
|
|
66
|
+
}
|
|
67
|
+
),
|
|
68
|
+
field.showButton && field.onButtonClick && /* @__PURE__ */ jsx(
|
|
69
|
+
"button",
|
|
70
|
+
{
|
|
71
|
+
className: "settings-button",
|
|
72
|
+
onClick: field.onButtonClick,
|
|
73
|
+
disabled: field.buttonDisabled || field.disabled,
|
|
74
|
+
children: field.buttonLabel || "Submit"
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
] }),
|
|
78
|
+
field.error && /* @__PURE__ */ jsx("p", { className: "settings-field-error", children: field.error })
|
|
79
|
+
] }, field.id);
|
|
80
|
+
case "select":
|
|
81
|
+
return /* @__PURE__ */ jsxs("div", { className: "settings-field", children: [
|
|
82
|
+
/* @__PURE__ */ jsx("label", { className: "settings-field-label", htmlFor: field.id, children: field.label }),
|
|
83
|
+
field.description && /* @__PURE__ */ jsx("p", { className: "settings-field-description", children: field.description }),
|
|
84
|
+
/* @__PURE__ */ jsx(
|
|
85
|
+
Select,
|
|
86
|
+
{
|
|
87
|
+
id: field.id,
|
|
88
|
+
className: "settings-select",
|
|
89
|
+
value: field.value,
|
|
90
|
+
onChange: field.onChange,
|
|
91
|
+
options: field.options,
|
|
92
|
+
disabled: field.disabled
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
] }, field.id);
|
|
96
|
+
case "button":
|
|
97
|
+
return /* @__PURE__ */ jsxs("div", { className: "settings-field", children: [
|
|
98
|
+
field.label && /* @__PURE__ */ jsx("label", { className: "settings-field-label", children: field.label }),
|
|
99
|
+
field.description && /* @__PURE__ */ jsx("p", { className: "settings-field-description", children: field.description }),
|
|
100
|
+
/* @__PURE__ */ jsx(
|
|
101
|
+
"button",
|
|
102
|
+
{
|
|
103
|
+
className: `settings-button settings-button--${field.variant || "default"}`,
|
|
104
|
+
onClick: field.onClick,
|
|
105
|
+
disabled: field.disabled,
|
|
106
|
+
children: field.buttonLabel
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
] }, field.id);
|
|
110
|
+
case "custom":
|
|
111
|
+
return /* @__PURE__ */ jsxs("div", { className: "settings-field", children: [
|
|
112
|
+
field.label && /* @__PURE__ */ jsx("label", { className: "settings-field-label", children: field.label }),
|
|
113
|
+
field.description && /* @__PURE__ */ jsx("p", { className: "settings-field-description", children: field.description }),
|
|
114
|
+
field.render()
|
|
115
|
+
] }, field.id);
|
|
116
|
+
default:
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
return /* @__PURE__ */ jsx(
|
|
121
|
+
Modal,
|
|
122
|
+
{
|
|
123
|
+
isOpen,
|
|
124
|
+
title,
|
|
125
|
+
onClose,
|
|
126
|
+
onConfirm: showCloseButton ? onClose : void 0,
|
|
127
|
+
confirmLabel: "Close",
|
|
128
|
+
showCancel: false,
|
|
129
|
+
showConfirm: showCloseButton,
|
|
130
|
+
className: `settings-modal ${className}`,
|
|
131
|
+
children: /* @__PURE__ */ jsx("div", { className: "settings-content", children: sections.map((section) => /* @__PURE__ */ jsxs("div", { className: "settings-section", children: [
|
|
132
|
+
/* @__PURE__ */ jsx("h4", { className: "settings-section-title", children: section.title }),
|
|
133
|
+
section.fields.map((field) => renderField(field))
|
|
134
|
+
] }, section.id)) })
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
export {
|
|
139
|
+
SettingsModal
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=SettingsModal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SettingsModal.js","sources":["../../src/components/SettingsModal.tsx"],"sourcesContent":["/**\n * SettingsModal Component\n * Generic settings dialog that can be customized with sections\n */\n\nimport React from 'react'\nimport { Modal } from './Modal'\nimport { Select } from './Select'\n\nexport interface SettingsSection {\n id: string\n title: string\n fields: SettingsField[]\n}\n\nexport type SettingsField =\n | SettingsToggleField\n | SettingsTextInputField\n | SettingsPasswordField\n | SettingsSelectField\n | SettingsButtonField\n | SettingsCustomField\n\nexport interface BaseSettingsField {\n id: string\n label: string\n description?: string\n disabled?: boolean\n}\n\nexport interface SettingsToggleField extends BaseSettingsField {\n type: 'toggle'\n value: boolean\n onChange: (value: boolean) => void\n}\n\nexport interface SettingsTextInputField extends BaseSettingsField {\n type: 'text'\n value: string\n onChange: (value: string) => void\n placeholder?: string\n}\n\nexport interface SettingsPasswordField extends BaseSettingsField {\n type: 'password'\n value: string\n onChange: (value: string) => void\n placeholder?: string\n showButton?: boolean\n buttonLabel?: string\n onButtonClick?: () => void | Promise<void>\n buttonDisabled?: boolean\n error?: string | null\n autoComplete?: string\n}\n\nexport interface SettingsSelectField extends BaseSettingsField {\n type: 'select'\n value: string\n onChange: (value: string) => void\n options: Array<{ value: string; label: string }>\n}\n\nexport interface SettingsButtonField extends BaseSettingsField {\n type: 'button'\n buttonLabel: string\n onClick: () => void | Promise<void>\n variant?: 'primary' | 'danger' | 'default'\n}\n\nexport interface SettingsCustomField extends BaseSettingsField {\n type: 'custom'\n render: () => React.ReactNode\n}\n\nexport interface SettingsModalProps {\n isOpen: boolean\n title?: string\n sections: SettingsSection[]\n onClose: () => void\n className?: string\n showCloseButton?: boolean\n}\n\nexport function SettingsModal({\n isOpen,\n title = 'Settings',\n sections,\n onClose,\n className = '',\n showCloseButton = true\n}: SettingsModalProps) {\n const renderField = (field: SettingsField) => {\n switch (field.type) {\n case 'toggle':\n return (\n <div key={field.id} className=\"settings-field\">\n <div className=\"settings-field-header\">\n <label className=\"settings-field-label\" htmlFor={field.id}>\n {field.label}\n </label>\n <input\n type=\"checkbox\"\n id={field.id}\n className=\"settings-toggle\"\n checked={field.value}\n onChange={e => field.onChange(e.target.checked)}\n disabled={field.disabled}\n />\n </div>\n {field.description && <p className=\"settings-field-description\">{field.description}</p>}\n </div>\n )\n\n case 'text':\n return (\n <div key={field.id} className=\"settings-field\">\n <label className=\"settings-field-label\" htmlFor={field.id}>\n {field.label}\n </label>\n {field.description && <p className=\"settings-field-description\">{field.description}</p>}\n <input\n type=\"text\"\n id={field.id}\n className=\"settings-text-input\"\n value={field.value}\n onChange={e => field.onChange(e.target.value)}\n placeholder={field.placeholder}\n disabled={field.disabled}\n />\n </div>\n )\n\n case 'password':\n return (\n <div key={field.id} className=\"settings-field\">\n <label className=\"settings-field-label\" htmlFor={field.id}>\n {field.label}\n </label>\n {field.description && <p className=\"settings-field-description\">{field.description}</p>}\n <div className=\"settings-field-input-group\">\n <input\n type=\"password\"\n id={field.id}\n name={field.autoComplete || field.id}\n autoComplete={field.autoComplete || 'off'}\n className=\"settings-text-input\"\n value={field.value}\n onChange={e => field.onChange(e.target.value)}\n placeholder={field.placeholder}\n disabled={field.disabled}\n />\n {field.showButton && field.onButtonClick && (\n <button\n className=\"settings-button\"\n onClick={field.onButtonClick}\n disabled={field.buttonDisabled || field.disabled}\n >\n {field.buttonLabel || 'Submit'}\n </button>\n )}\n </div>\n {field.error && <p className=\"settings-field-error\">{field.error}</p>}\n </div>\n )\n\n case 'select':\n return (\n <div key={field.id} className=\"settings-field\">\n <label className=\"settings-field-label\" htmlFor={field.id}>\n {field.label}\n </label>\n {field.description && <p className=\"settings-field-description\">{field.description}</p>}\n <Select\n id={field.id}\n className=\"settings-select\"\n value={field.value}\n onChange={field.onChange}\n options={field.options}\n disabled={field.disabled}\n />\n </div>\n )\n\n case 'button':\n return (\n <div key={field.id} className=\"settings-field\">\n {field.label && <label className=\"settings-field-label\">{field.label}</label>}\n {field.description && <p className=\"settings-field-description\">{field.description}</p>}\n <button\n className={`settings-button settings-button--${field.variant || 'default'}`}\n onClick={field.onClick}\n disabled={field.disabled}\n >\n {field.buttonLabel}\n </button>\n </div>\n )\n\n case 'custom':\n return (\n <div key={field.id} className=\"settings-field\">\n {field.label && <label className=\"settings-field-label\">{field.label}</label>}\n {field.description && <p className=\"settings-field-description\">{field.description}</p>}\n {field.render()}\n </div>\n )\n\n default:\n return null\n }\n }\n\n return (\n <Modal\n isOpen={isOpen}\n title={title}\n onClose={onClose}\n onConfirm={showCloseButton ? onClose : undefined}\n confirmLabel=\"Close\"\n showCancel={false}\n showConfirm={showCloseButton}\n className={`settings-modal ${className}`}\n >\n <div className=\"settings-content\">\n {sections.map(section => (\n <div key={section.id} className=\"settings-section\">\n <h4 className=\"settings-section-title\">{section.title}</h4>\n {section.fields.map(field => renderField(field))}\n </div>\n ))}\n </div>\n </Modal>\n )\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component icons - Simple monochrome SVG icons for theme picker
|
|
3
|
+
* All icons use currentColor so they can be styled with CSS
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
export declare const SettingsIcon: () => React.JSX.Element;
|
|
7
|
+
export declare const TagIcon: () => React.JSX.Element;
|
|
8
|
+
export declare const CircleIcon: () => React.JSX.Element;
|
|
9
|
+
export declare const SquareIcon: () => React.JSX.Element;
|
|
10
|
+
export declare const TriangleIcon: () => React.JSX.Element;
|
|
11
|
+
export declare const DiamondIcon: () => React.JSX.Element;
|
|
12
|
+
export declare const StarIcon: () => React.JSX.Element;
|
|
13
|
+
export declare const HexagonIcon: () => React.JSX.Element;
|
|
14
|
+
export declare const PentagonIcon: () => React.JSX.Element;
|
|
15
|
+
export declare const OctagonIcon: () => React.JSX.Element;
|
|
16
|
+
/**
|
|
17
|
+
* Fallback icon sets for themes - provides 8 distinct shapes
|
|
18
|
+
* Use these when you don't have specific icons for your themes
|
|
19
|
+
*/
|
|
20
|
+
export declare const FALLBACK_ICONS: readonly [() => React.JSX.Element, () => React.JSX.Element, () => React.JSX.Element, () => React.JSX.Element, () => React.JSX.Element, () => React.JSX.Element, () => React.JSX.Element, () => React.JSX.Element];
|
|
21
|
+
/**
|
|
22
|
+
* Get a fallback icon for a theme by index
|
|
23
|
+
* Icons repeat after 8 themes to provide consistent differentiation
|
|
24
|
+
*/
|
|
25
|
+
export declare function getFallbackIcon(index: number): React.JSX.Element;
|
|
26
|
+
//# sourceMappingURL=ThemeIcons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThemeIcons.d.ts","sourceRoot":"","sources":["../../src/components/ThemeIcons.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAA;AAazB,eAAO,MAAM,YAAY,yBAyBxB,CAAA;AAED,eAAO,MAAM,OAAO,yBAOnB,CAAA;AAED,eAAO,MAAM,UAAU,yBAItB,CAAA;AAED,eAAO,MAAM,UAAU,yBAItB,CAAA;AAED,eAAO,MAAM,YAAY,yBAIxB,CAAA;AAED,eAAO,MAAM,WAAW,yBAIvB,CAAA;AAED,eAAO,MAAM,QAAQ,yBAIpB,CAAA;AAED,eAAO,MAAM,WAAW,yBAIvB,CAAA;AAED,eAAO,MAAM,YAAY,yBAIxB,CAAA;AAED,eAAO,MAAM,WAAW,yBAIvB,CAAA;AAED;;;GAGG;AAEH,eAAO,MAAM,cAAc,mNASjB,CAAA;AAEV;;;GAGG;AAEH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,qBAG5C"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
const iconProps = {
|
|
3
|
+
width: 20,
|
|
4
|
+
height: 20,
|
|
5
|
+
viewBox: "0 0 24 24",
|
|
6
|
+
fill: "none",
|
|
7
|
+
stroke: "currentColor",
|
|
8
|
+
strokeWidth: 2,
|
|
9
|
+
strokeLinecap: "round",
|
|
10
|
+
strokeLinejoin: "round"
|
|
11
|
+
};
|
|
12
|
+
const SettingsIcon = () => /* @__PURE__ */ jsxs("svg", { ...iconProps, children: [
|
|
13
|
+
/* @__PURE__ */ jsx("rect", { x: "11", y: "1", width: "2", height: "3", fill: "currentColor" }),
|
|
14
|
+
/* @__PURE__ */ jsx("rect", { x: "16.5", y: "3.5", width: "3", height: "2", fill: "currentColor", transform: "rotate(45 18 4.5)" }),
|
|
15
|
+
/* @__PURE__ */ jsx("rect", { x: "19", y: "11", width: "3", height: "2", fill: "currentColor" }),
|
|
16
|
+
/* @__PURE__ */ jsx(
|
|
17
|
+
"rect",
|
|
18
|
+
{
|
|
19
|
+
x: "16.5",
|
|
20
|
+
y: "18.5",
|
|
21
|
+
width: "3",
|
|
22
|
+
height: "2",
|
|
23
|
+
fill: "currentColor",
|
|
24
|
+
transform: "rotate(-45 18 19.5)"
|
|
25
|
+
}
|
|
26
|
+
),
|
|
27
|
+
/* @__PURE__ */ jsx("rect", { x: "11", y: "20", width: "2", height: "3", fill: "currentColor" }),
|
|
28
|
+
/* @__PURE__ */ jsx("rect", { x: "4.5", y: "18.5", width: "3", height: "2", fill: "currentColor", transform: "rotate(45 6 19.5)" }),
|
|
29
|
+
/* @__PURE__ */ jsx("rect", { x: "2", y: "11", width: "3", height: "2", fill: "currentColor" }),
|
|
30
|
+
/* @__PURE__ */ jsx("rect", { x: "4.5", y: "3.5", width: "3", height: "2", fill: "currentColor", transform: "rotate(-45 6 4.5)" }),
|
|
31
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "7", fill: "currentColor" }),
|
|
32
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "4", fill: "var(--color-bg-card)" })
|
|
33
|
+
] });
|
|
34
|
+
const TagIcon = () => /* @__PURE__ */ jsxs("svg", { ...iconProps, width: 16, height: 16, viewBox: "0 0 20 20", children: [
|
|
35
|
+
/* @__PURE__ */ jsx("path", { d: "M2 4 L12 4 L16 10 L12 16 L2 16 Z", fill: "currentColor" }),
|
|
36
|
+
/* @__PURE__ */ jsx("circle", { cx: "6", cy: "10", r: "1.5", fill: "white" })
|
|
37
|
+
] });
|
|
38
|
+
const CircleIcon = () => /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "8" }) });
|
|
39
|
+
const SquareIcon = () => /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx("rect", { x: "5", y: "5", width: "14", height: "14", rx: "2" }) });
|
|
40
|
+
const TriangleIcon = () => /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx("path", { d: "M12 5 L21 19 L3 19 Z" }) });
|
|
41
|
+
const DiamondIcon = () => /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx("path", { d: "M12 2 L22 12 L12 22 L2 12 Z" }) });
|
|
42
|
+
const StarIcon = () => /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx("polygon", { points: "12,2 15,10 23,10 17,15 19,23 12,18 5,23 7,15 1,10 9,10" }) });
|
|
43
|
+
const HexagonIcon = () => /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx("path", { d: "M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" }) });
|
|
44
|
+
const PentagonIcon = () => /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx("path", { d: "M12 2 L22 9 L18 20 L6 20 L2 9 Z" }) });
|
|
45
|
+
const OctagonIcon = () => /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx("polygon", { points: "7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86" }) });
|
|
46
|
+
const FALLBACK_ICONS = [
|
|
47
|
+
CircleIcon,
|
|
48
|
+
SquareIcon,
|
|
49
|
+
TriangleIcon,
|
|
50
|
+
DiamondIcon,
|
|
51
|
+
StarIcon,
|
|
52
|
+
HexagonIcon,
|
|
53
|
+
PentagonIcon,
|
|
54
|
+
OctagonIcon
|
|
55
|
+
];
|
|
56
|
+
function getFallbackIcon(index) {
|
|
57
|
+
const Icon = FALLBACK_ICONS[index % FALLBACK_ICONS.length];
|
|
58
|
+
return /* @__PURE__ */ jsx(Icon, {});
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
CircleIcon,
|
|
62
|
+
DiamondIcon,
|
|
63
|
+
FALLBACK_ICONS,
|
|
64
|
+
HexagonIcon,
|
|
65
|
+
OctagonIcon,
|
|
66
|
+
PentagonIcon,
|
|
67
|
+
SettingsIcon,
|
|
68
|
+
SquareIcon,
|
|
69
|
+
StarIcon,
|
|
70
|
+
TagIcon,
|
|
71
|
+
TriangleIcon,
|
|
72
|
+
getFallbackIcon
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=ThemeIcons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThemeIcons.js","sources":["../../src/components/ThemeIcons.tsx"],"sourcesContent":["/**\n * Component icons - Simple monochrome SVG icons for theme picker\n * All icons use currentColor so they can be styled with CSS\n */\n\nimport React from 'react'\n\nconst iconProps = {\n width: 20,\n height: 20,\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 2,\n strokeLinecap: 'round' as const,\n strokeLinejoin: 'round' as const\n}\n\nexport const SettingsIcon = () => (\n <svg {...iconProps}>\n {/* Gear teeth as rectangles */}\n <rect x=\"11\" y=\"1\" width=\"2\" height=\"3\" fill=\"currentColor\" />\n <rect x=\"16.5\" y=\"3.5\" width=\"3\" height=\"2\" fill=\"currentColor\" transform=\"rotate(45 18 4.5)\" />\n <rect x=\"19\" y=\"11\" width=\"3\" height=\"2\" fill=\"currentColor\" />\n <rect\n x=\"16.5\"\n y=\"18.5\"\n width=\"3\"\n height=\"2\"\n fill=\"currentColor\"\n transform=\"rotate(-45 18 19.5)\"\n />\n <rect x=\"11\" y=\"20\" width=\"2\" height=\"3\" fill=\"currentColor\" />\n <rect x=\"4.5\" y=\"18.5\" width=\"3\" height=\"2\" fill=\"currentColor\" transform=\"rotate(45 6 19.5)\" />\n <rect x=\"2\" y=\"11\" width=\"3\" height=\"2\" fill=\"currentColor\" />\n <rect x=\"4.5\" y=\"3.5\" width=\"3\" height=\"2\" fill=\"currentColor\" transform=\"rotate(-45 6 4.5)\" />\n\n {/* Outer ring */}\n <circle cx=\"12\" cy=\"12\" r=\"7\" fill=\"currentColor\" />\n\n {/* Center hole */}\n <circle cx=\"12\" cy=\"12\" r=\"4\" fill=\"var(--color-bg-card)\" />\n </svg>\n)\n\nexport const TagIcon = () => (\n <svg {...iconProps} width={16} height={16} viewBox=\"0 0 20 20\">\n {/* Tag body - rectangular shape pointing right */}\n <path d=\"M2 4 L12 4 L16 10 L12 16 L2 16 Z\" fill=\"currentColor\" />\n {/* Hole in tag */}\n <circle cx=\"6\" cy=\"10\" r=\"1.5\" fill=\"white\" />\n </svg>\n)\n\nexport const CircleIcon = () => (\n <svg {...iconProps}>\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n)\n\nexport const SquareIcon = () => (\n <svg {...iconProps}>\n <rect x=\"5\" y=\"5\" width=\"14\" height=\"14\" rx=\"2\" />\n </svg>\n)\n\nexport const TriangleIcon = () => (\n <svg {...iconProps}>\n <path d=\"M12 5 L21 19 L3 19 Z\" />\n </svg>\n)\n\nexport const DiamondIcon = () => (\n <svg {...iconProps}>\n <path d=\"M12 2 L22 12 L12 22 L2 12 Z\" />\n </svg>\n)\n\nexport const StarIcon = () => (\n <svg {...iconProps}>\n <polygon points=\"12,2 15,10 23,10 17,15 19,23 12,18 5,23 7,15 1,10 9,10\" />\n </svg>\n)\n\nexport const HexagonIcon = () => (\n <svg {...iconProps}>\n <path d=\"M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z\" />\n </svg>\n)\n\nexport const PentagonIcon = () => (\n <svg {...iconProps}>\n <path d=\"M12 2 L22 9 L18 20 L6 20 L2 9 Z\" />\n </svg>\n)\n\nexport const OctagonIcon = () => (\n <svg {...iconProps}>\n <polygon points=\"7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86\" />\n </svg>\n)\n\n/**\n * Fallback icon sets for themes - provides 8 distinct shapes\n * Use these when you don't have specific icons for your themes\n */\n\nexport const FALLBACK_ICONS = [\n CircleIcon,\n SquareIcon,\n TriangleIcon,\n DiamondIcon,\n StarIcon,\n HexagonIcon,\n PentagonIcon,\n OctagonIcon\n] as const\n\n/**\n * Get a fallback icon for a theme by index\n * Icons repeat after 8 themes to provide consistent differentiation\n */\n\nexport function getFallbackIcon(index: number) {\n const Icon = FALLBACK_ICONS[index % FALLBACK_ICONS.length]\n return <Icon />\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ThemePicker component
|
|
3
|
+
* A beautiful theme picker with light/dark variants for each theme family
|
|
4
|
+
* Designed to work with any theme system via configuration
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import type { ThemePickerProps } from '../types';
|
|
8
|
+
import '../theme-picker.css';
|
|
9
|
+
/**
|
|
10
|
+
* ThemePicker - Dropdown theme selector with optional settings button
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* import { ThemePicker } from '@wolffm/task-ui-components'
|
|
15
|
+
* import '@wolffm/task-ui-components/theme-picker.css'
|
|
16
|
+
*
|
|
17
|
+
* <ThemePicker
|
|
18
|
+
* currentTheme="dark"
|
|
19
|
+
* isOpen={showPicker}
|
|
20
|
+
* themeFamilies={MY_THEME_FAMILIES}
|
|
21
|
+
* onThemeChange={setTheme}
|
|
22
|
+
* onToggle={() => setShowPicker(!showPicker)}
|
|
23
|
+
* onSettingsClick={() => openSettings()}
|
|
24
|
+
* />
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function ThemePicker({ currentTheme, isOpen, themeFamilies, onThemeChange, onToggle, onSettingsClick, getThemeIcon, className, dropdownPlacement }: ThemePickerProps): React.JSX.Element;
|
|
28
|
+
//# sourceMappingURL=ThemePicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThemePicker.d.ts","sourceRoot":"","sources":["../../src/components/ThemePicker.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAA4C,MAAM,OAAO,CAAA;AAEhE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAIhD,OAAO,qBAAqB,CAAA;AAE5B;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,YAAY,EACZ,MAAM,EACN,aAAa,EACb,aAAa,EACb,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,SAAc,EACd,iBAA0B,EAC3B,EAAE,gBAAgB,qBA0GlB"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState, useLayoutEffect } from "react";
|
|
3
|
+
import { Tooltip } from "./Tooltip.js";
|
|
4
|
+
import { getFallbackIcon, SettingsIcon } from "./ThemeIcons.js";
|
|
5
|
+
import { MoonIcon } from "@wolffm/themes";
|
|
6
|
+
/* empty css */
|
|
7
|
+
function ThemePicker({
|
|
8
|
+
currentTheme,
|
|
9
|
+
isOpen,
|
|
10
|
+
themeFamilies,
|
|
11
|
+
onThemeChange,
|
|
12
|
+
onToggle,
|
|
13
|
+
onSettingsClick,
|
|
14
|
+
getThemeIcon,
|
|
15
|
+
className = "",
|
|
16
|
+
dropdownPlacement = "auto"
|
|
17
|
+
}) {
|
|
18
|
+
const dropdownRef = useRef(null);
|
|
19
|
+
const [resolvedPlacement, setResolvedPlacement] = useState("right");
|
|
20
|
+
useLayoutEffect(() => {
|
|
21
|
+
if (!isOpen) return;
|
|
22
|
+
if (dropdownPlacement !== "auto") {
|
|
23
|
+
setResolvedPlacement(dropdownPlacement);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
setResolvedPlacement("right");
|
|
27
|
+
const frameId = requestAnimationFrame(() => {
|
|
28
|
+
const el = dropdownRef.current;
|
|
29
|
+
if (!el) return;
|
|
30
|
+
const rect = el.getBoundingClientRect();
|
|
31
|
+
if (rect.right > window.innerWidth) {
|
|
32
|
+
setResolvedPlacement("left");
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return () => cancelAnimationFrame(frameId);
|
|
36
|
+
}, [isOpen, dropdownPlacement]);
|
|
37
|
+
const currentIcon = getThemeIcon ? getThemeIcon(currentTheme) : /* @__PURE__ */ jsx(MoonIcon, {});
|
|
38
|
+
const openLeftClass = resolvedPlacement === "left" ? "theme-picker--open-left" : "";
|
|
39
|
+
return /* @__PURE__ */ jsxs("div", { className: `theme-picker ${openLeftClass} ${className}`.trim(), children: [
|
|
40
|
+
/* @__PURE__ */ jsx(Tooltip, { content: "Choose theme", children: /* @__PURE__ */ jsx(
|
|
41
|
+
"button",
|
|
42
|
+
{
|
|
43
|
+
className: "app-header__icon-btn theme-toggle-btn",
|
|
44
|
+
onClick: onToggle,
|
|
45
|
+
"aria-label": "Choose theme",
|
|
46
|
+
children: currentIcon
|
|
47
|
+
}
|
|
48
|
+
) }),
|
|
49
|
+
isOpen && /* @__PURE__ */ jsx(
|
|
50
|
+
"div",
|
|
51
|
+
{
|
|
52
|
+
ref: dropdownRef,
|
|
53
|
+
className: "theme-picker__dropdown",
|
|
54
|
+
onClick: (e) => e.stopPropagation(),
|
|
55
|
+
children: /* @__PURE__ */ jsxs("div", { className: "theme-picker__main", children: [
|
|
56
|
+
/* @__PURE__ */ jsx("div", { className: "theme-picker__pills", children: themeFamilies.map((family, idx) => {
|
|
57
|
+
const lightIcon = family.lightIcon ?? getFallbackIcon(idx);
|
|
58
|
+
const darkIcon = family.darkIcon ?? getFallbackIcon(idx);
|
|
59
|
+
return /* @__PURE__ */ jsxs("div", { className: "theme-pill", children: [
|
|
60
|
+
/* @__PURE__ */ jsx(Tooltip, { content: family.lightLabel, children: /* @__PURE__ */ jsx(
|
|
61
|
+
"button",
|
|
62
|
+
{
|
|
63
|
+
className: `theme-pill__btn theme-pill__btn--light ${currentTheme === family.lightTheme ? "active" : ""}`,
|
|
64
|
+
onClick: () => onThemeChange(family.lightTheme),
|
|
65
|
+
"aria-label": family.lightLabel,
|
|
66
|
+
children: /* @__PURE__ */ jsx("div", { className: "theme-pill__icon", children: lightIcon })
|
|
67
|
+
}
|
|
68
|
+
) }),
|
|
69
|
+
/* @__PURE__ */ jsx(Tooltip, { content: family.darkLabel, children: /* @__PURE__ */ jsx(
|
|
70
|
+
"button",
|
|
71
|
+
{
|
|
72
|
+
className: `theme-pill__btn theme-pill__btn--dark ${currentTheme === family.darkTheme ? "active" : ""}`,
|
|
73
|
+
onClick: () => onThemeChange(family.darkTheme),
|
|
74
|
+
"aria-label": family.darkLabel,
|
|
75
|
+
children: /* @__PURE__ */ jsx("div", { className: "theme-pill__icon", children: darkIcon })
|
|
76
|
+
}
|
|
77
|
+
) })
|
|
78
|
+
] }, idx);
|
|
79
|
+
}) }),
|
|
80
|
+
onSettingsClick && /* @__PURE__ */ jsx(Tooltip, { content: "Settings", children: /* @__PURE__ */ jsx(
|
|
81
|
+
"button",
|
|
82
|
+
{
|
|
83
|
+
className: "theme-picker__settings-icon",
|
|
84
|
+
onClick: () => {
|
|
85
|
+
onSettingsClick();
|
|
86
|
+
onToggle();
|
|
87
|
+
},
|
|
88
|
+
"aria-label": "Settings",
|
|
89
|
+
children: /* @__PURE__ */ jsx(SettingsIcon, {})
|
|
90
|
+
}
|
|
91
|
+
) })
|
|
92
|
+
] })
|
|
93
|
+
}
|
|
94
|
+
),
|
|
95
|
+
isOpen && /* @__PURE__ */ jsx("div", { className: "theme-picker__overlay", onClick: onToggle })
|
|
96
|
+
] });
|
|
97
|
+
}
|
|
98
|
+
export {
|
|
99
|
+
ThemePicker
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=ThemePicker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThemePicker.js","sources":["../../src/components/ThemePicker.tsx"],"sourcesContent":["/**\n * ThemePicker component\n * A beautiful theme picker with light/dark variants for each theme family\n * Designed to work with any theme system via configuration\n */\n\nimport React, { useRef, useLayoutEffect, useState } from 'react'\nimport { Tooltip } from './Tooltip'\nimport type { ThemePickerProps } from '../types'\nimport { SettingsIcon, getFallbackIcon } from './ThemeIcons'\n// MoonIcon is a theme-family icon and lives with the theme model now.\nimport { MoonIcon } from '@wolffm/themes'\nimport '../theme-picker.css'\n\n/**\n * ThemePicker - Dropdown theme selector with optional settings button\n *\n * @example\n * ```tsx\n * import { ThemePicker } from '@wolffm/task-ui-components'\n * import '@wolffm/task-ui-components/theme-picker.css'\n *\n * <ThemePicker\n * currentTheme=\"dark\"\n * isOpen={showPicker}\n * themeFamilies={MY_THEME_FAMILIES}\n * onThemeChange={setTheme}\n * onToggle={() => setShowPicker(!showPicker)}\n * onSettingsClick={() => openSettings()}\n * />\n * ```\n */\nexport function ThemePicker({\n currentTheme,\n isOpen,\n themeFamilies,\n onThemeChange,\n onToggle,\n onSettingsClick,\n getThemeIcon,\n className = '',\n dropdownPlacement = 'auto'\n}: ThemePickerProps) {\n const dropdownRef = useRef<HTMLDivElement>(null)\n const [resolvedPlacement, setResolvedPlacement] = useState<'left' | 'right'>('right')\n\n // Edge detection: when 'auto', measure the dropdown after render and flip if it overflows\n useLayoutEffect(() => {\n if (!isOpen) return\n\n if (dropdownPlacement !== 'auto') {\n setResolvedPlacement(dropdownPlacement)\n return\n }\n\n // Start with right (default), then check if it overflows\n setResolvedPlacement('right')\n\n // Use rAF to measure after the browser has laid out the dropdown\n const frameId = requestAnimationFrame(() => {\n const el = dropdownRef.current\n if (!el) return\n const rect = el.getBoundingClientRect()\n if (rect.right > window.innerWidth) {\n setResolvedPlacement('left')\n }\n })\n\n return () => cancelAnimationFrame(frameId)\n }, [isOpen, dropdownPlacement])\n\n // Get icon for current theme (use provided function or fallback to MoonIcon)\n const currentIcon = getThemeIcon ? getThemeIcon(currentTheme) : <MoonIcon />\n\n const openLeftClass = resolvedPlacement === 'left' ? 'theme-picker--open-left' : ''\n\n return (\n <div className={`theme-picker ${openLeftClass} ${className}`.trim()}>\n <Tooltip content=\"Choose theme\">\n <button\n className=\"app-header__icon-btn theme-toggle-btn\"\n onClick={onToggle}\n aria-label=\"Choose theme\"\n >\n {currentIcon}\n </button>\n </Tooltip>\n {isOpen && (\n <div\n ref={dropdownRef}\n className=\"theme-picker__dropdown\"\n onClick={e => e.stopPropagation()}\n >\n <div className=\"theme-picker__main\">\n <div className=\"theme-picker__pills\">\n {themeFamilies.map((family, idx) => {\n // Use provided icons or fallback to generic shapes\n const lightIcon = family.lightIcon ?? getFallbackIcon(idx)\n const darkIcon = family.darkIcon ?? getFallbackIcon(idx)\n\n return (\n <div key={idx} className=\"theme-pill\">\n {/* Light variant button */}\n <Tooltip content={family.lightLabel}>\n <button\n className={`theme-pill__btn theme-pill__btn--light ${currentTheme === family.lightTheme ? 'active' : ''}`}\n onClick={() => onThemeChange(family.lightTheme)}\n aria-label={family.lightLabel}\n >\n <div className=\"theme-pill__icon\">{lightIcon}</div>\n </button>\n </Tooltip>\n\n {/* Dark variant button */}\n <Tooltip content={family.darkLabel}>\n <button\n className={`theme-pill__btn theme-pill__btn--dark ${currentTheme === family.darkTheme ? 'active' : ''}`}\n onClick={() => onThemeChange(family.darkTheme)}\n aria-label={family.darkLabel}\n >\n <div className=\"theme-pill__icon\">{darkIcon}</div>\n </button>\n </Tooltip>\n </div>\n )\n })}\n </div>\n {/* Settings button - separate column on the right */}\n {onSettingsClick && (\n <Tooltip content=\"Settings\">\n <button\n className=\"theme-picker__settings-icon\"\n onClick={() => {\n onSettingsClick()\n onToggle() // Close picker after opening settings\n }}\n aria-label=\"Settings\"\n >\n <SettingsIcon />\n </button>\n </Tooltip>\n )}\n </div>\n </div>\n )}\n {isOpen && <div className=\"theme-picker__overlay\" onClick={onToggle} />}\n </div>\n )\n}\n"],"names":[],"mappings":";;;;;;AAgCO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,oBAAoB;AACtB,GAAqB;AACnB,QAAM,cAAc,OAAuB,IAAI;AAC/C,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAA2B,OAAO;AAGpF,kBAAgB,MAAM;AACpB,QAAI,CAAC,OAAQ;AAEb,QAAI,sBAAsB,QAAQ;AAChC,2BAAqB,iBAAiB;AACtC;AAAA,IACF;AAGA,yBAAqB,OAAO;AAG5B,UAAM,UAAU,sBAAsB,MAAM;AAC1C,YAAM,KAAK,YAAY;AACvB,UAAI,CAAC,GAAI;AACT,YAAM,OAAO,GAAG,sBAAA;AAChB,UAAI,KAAK,QAAQ,OAAO,YAAY;AAClC,6BAAqB,MAAM;AAAA,MAC7B;AAAA,IACF,CAAC;AAED,WAAO,MAAM,qBAAqB,OAAO;AAAA,EAC3C,GAAG,CAAC,QAAQ,iBAAiB,CAAC;AAG9B,QAAM,cAAc,eAAe,aAAa,YAAY,wBAAK,UAAA,EAAS;AAE1E,QAAM,gBAAgB,sBAAsB,SAAS,4BAA4B;AAEjF,SACE,qBAAC,SAAI,WAAW,gBAAgB,aAAa,IAAI,SAAS,GAAG,KAAA,GAC3D,UAAA;AAAA,IAAA,oBAAC,SAAA,EAAQ,SAAQ,gBACf,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS;AAAA,QACT,cAAW;AAAA,QAEV,UAAA;AAAA,MAAA;AAAA,IAAA,GAEL;AAAA,IACC,UACC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,CAAA,MAAK,EAAE,gBAAA;AAAA,QAEhB,UAAA,qBAAC,OAAA,EAAI,WAAU,sBACb,UAAA;AAAA,UAAA,oBAAC,SAAI,WAAU,uBACZ,wBAAc,IAAI,CAAC,QAAQ,QAAQ;AAElC,kBAAM,YAAY,OAAO,aAAa,gBAAgB,GAAG;AACzD,kBAAM,WAAW,OAAO,YAAY,gBAAgB,GAAG;AAEvD,mBACE,qBAAC,OAAA,EAAc,WAAU,cAEvB,UAAA;AAAA,cAAA,oBAAC,SAAA,EAAQ,SAAS,OAAO,YACvB,UAAA;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,WAAW,0CAA0C,iBAAiB,OAAO,aAAa,WAAW,EAAE;AAAA,kBACvG,SAAS,MAAM,cAAc,OAAO,UAAU;AAAA,kBAC9C,cAAY,OAAO;AAAA,kBAEnB,UAAA,oBAAC,OAAA,EAAI,WAAU,oBAAoB,UAAA,UAAA,CAAU;AAAA,gBAAA;AAAA,cAAA,GAEjD;AAAA,cAGA,oBAAC,SAAA,EAAQ,SAAS,OAAO,WACvB,UAAA;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,WAAW,yCAAyC,iBAAiB,OAAO,YAAY,WAAW,EAAE;AAAA,kBACrG,SAAS,MAAM,cAAc,OAAO,SAAS;AAAA,kBAC7C,cAAY,OAAO;AAAA,kBAEnB,UAAA,oBAAC,OAAA,EAAI,WAAU,oBAAoB,UAAA,SAAA,CAAS;AAAA,gBAAA;AAAA,cAAA,EAC9C,CACF;AAAA,YAAA,EAAA,GArBQ,GAsBV;AAAA,UAEJ,CAAC,EAAA,CACH;AAAA,UAEC,mBACC,oBAAC,SAAA,EAAQ,SAAQ,YACf,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,MAAM;AACb,gCAAA;AACA,yBAAA;AAAA,cACF;AAAA,cACA,cAAW;AAAA,cAEX,8BAAC,cAAA,CAAA,CAAa;AAAA,YAAA;AAAA,UAAA,EAChB,CACF;AAAA,QAAA,EAAA,CAEJ;AAAA,MAAA;AAAA,IAAA;AAAA,IAGH,UAAU,oBAAC,OAAA,EAAI,WAAU,yBAAwB,SAAS,SAAA,CAAU;AAAA,EAAA,GACvE;AAEJ;"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toast Notification Component
|
|
3
|
+
* Displays temporary notification messages with different types
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
export interface ToastProps {
|
|
7
|
+
message: string;
|
|
8
|
+
type?: 'success' | 'error' | 'info' | 'warning';
|
|
9
|
+
duration?: number;
|
|
10
|
+
onClose: () => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function Toast({ message, type, duration, onClose }: ToastProps): React.JSX.Element;
|
|
13
|
+
//# sourceMappingURL=Toast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../../src/components/Toast.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAA;AAElD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAmBD,wBAAgB,KAAK,CAAC,EAAE,OAAO,EAAE,IAAa,EAAE,QAAe,EAAE,OAAO,EAAE,EAAE,UAAU,qBA4DrF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
const renderIcon = (children) => /* @__PURE__ */ jsx(
|
|
4
|
+
"svg",
|
|
5
|
+
{
|
|
6
|
+
className: "toast__icon",
|
|
7
|
+
width: "20",
|
|
8
|
+
height: "20",
|
|
9
|
+
viewBox: "0 0 24 24",
|
|
10
|
+
fill: "none",
|
|
11
|
+
stroke: "currentColor",
|
|
12
|
+
strokeWidth: "2",
|
|
13
|
+
children
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
function Toast({ message, type = "info", duration = 3e3, onClose }) {
|
|
17
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const showTimer = setTimeout(() => {
|
|
20
|
+
setIsVisible(true);
|
|
21
|
+
}, 50);
|
|
22
|
+
const hideTimer = setTimeout(() => {
|
|
23
|
+
setIsVisible(false);
|
|
24
|
+
setTimeout(onClose, 500);
|
|
25
|
+
}, duration);
|
|
26
|
+
return () => {
|
|
27
|
+
clearTimeout(showTimer);
|
|
28
|
+
clearTimeout(hideTimer);
|
|
29
|
+
};
|
|
30
|
+
}, [duration, onClose]);
|
|
31
|
+
const getIcon = () => {
|
|
32
|
+
switch (type) {
|
|
33
|
+
case "success":
|
|
34
|
+
return renderIcon(/* @__PURE__ */ jsx("path", { d: "M20 6L9 17l-5-5" }));
|
|
35
|
+
case "error":
|
|
36
|
+
return renderIcon(
|
|
37
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
39
|
+
/* @__PURE__ */ jsx("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
|
|
40
|
+
/* @__PURE__ */ jsx("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
|
|
41
|
+
] })
|
|
42
|
+
);
|
|
43
|
+
case "warning":
|
|
44
|
+
return renderIcon(
|
|
45
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
46
|
+
/* @__PURE__ */ jsx("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
|
|
47
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
|
|
48
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
|
|
49
|
+
] })
|
|
50
|
+
);
|
|
51
|
+
case "info":
|
|
52
|
+
default:
|
|
53
|
+
return renderIcon(
|
|
54
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
55
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
56
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
|
|
57
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
|
|
58
|
+
] })
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
return /* @__PURE__ */ jsxs("div", { className: `toast toast--${type} ${isVisible ? "toast--visible" : ""}`, children: [
|
|
63
|
+
getIcon(),
|
|
64
|
+
/* @__PURE__ */ jsx("span", { className: "toast__message", children: message })
|
|
65
|
+
] });
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
Toast
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=Toast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toast.js","sources":["../../src/components/Toast.tsx"],"sourcesContent":["/**\r\n * Toast Notification Component\r\n * Displays temporary notification messages with different types\r\n */\r\n\r\nimport React, { useEffect, useState } from 'react'\r\n\r\nexport interface ToastProps {\r\n message: string\r\n type?: 'success' | 'error' | 'info' | 'warning'\r\n duration?: number\r\n onClose: () => void\r\n}\r\n\r\n/**\r\n * Helper function to render SVG icon wrapper with consistent styling\r\n */\r\nconst renderIcon = (children: React.ReactNode) => (\r\n <svg\r\n className=\"toast__icon\"\r\n width=\"20\"\r\n height=\"20\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n >\r\n {children}\r\n </svg>\r\n)\r\n\r\nexport function Toast({ message, type = 'info', duration = 3000, onClose }: ToastProps) {\r\n const [isVisible, setIsVisible] = useState(false)\r\n\r\n useEffect(() => {\r\n // Fade in with slight delay for smoother appearance\r\n const showTimer = setTimeout(() => {\r\n setIsVisible(true)\r\n }, 50)\r\n\r\n // Auto-dismiss after duration\r\n const hideTimer = setTimeout(() => {\r\n setIsVisible(false)\r\n // Wait for fade-out animation before calling onClose\r\n setTimeout(onClose, 500)\r\n }, duration)\r\n\r\n return () => {\r\n clearTimeout(showTimer)\r\n clearTimeout(hideTimer)\r\n }\r\n }, [duration, onClose])\r\n\r\n const getIcon = () => {\r\n switch (type) {\r\n case 'success':\r\n return renderIcon(<path d=\"M20 6L9 17l-5-5\" />)\r\n case 'error':\r\n return renderIcon(\r\n <>\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\" />\r\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\" />\r\n </>\r\n )\r\n case 'warning':\r\n return renderIcon(\r\n <>\r\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\" />\r\n <line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\" />\r\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\" />\r\n </>\r\n )\r\n case 'info':\r\n default:\r\n return renderIcon(\r\n <>\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\" />\r\n <line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\" />\r\n </>\r\n )\r\n }\r\n }\r\n\r\n return (\r\n <div className={`toast toast--${type} ${isVisible ? 'toast--visible' : ''}`}>\r\n {getIcon()}\r\n <span className=\"toast__message\">{message}</span>\r\n </div>\r\n )\r\n}\r\n"],"names":[],"mappings":";;AAiBA,MAAM,aAAa,CAAC,aAClB;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,WAAU;AAAA,IACV,OAAM;AAAA,IACN,QAAO;AAAA,IACP,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,QAAO;AAAA,IACP,aAAY;AAAA,IAEX;AAAA,EAAA;AACH;AAGK,SAAS,MAAM,EAAE,SAAS,OAAO,QAAQ,WAAW,KAAM,WAAuB;AACtF,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAEhD,YAAU,MAAM;AAEd,UAAM,YAAY,WAAW,MAAM;AACjC,mBAAa,IAAI;AAAA,IACnB,GAAG,EAAE;AAGL,UAAM,YAAY,WAAW,MAAM;AACjC,mBAAa,KAAK;AAElB,iBAAW,SAAS,GAAG;AAAA,IACzB,GAAG,QAAQ;AAEX,WAAO,MAAM;AACX,mBAAa,SAAS;AACtB,mBAAa,SAAS;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,QAAM,UAAU,MAAM;AACpB,YAAQ,MAAA;AAAA,MACN,KAAK;AACH,eAAO,WAAW,oBAAC,QAAA,EAAK,GAAE,mBAAkB,CAAE;AAAA,MAChD,KAAK;AACH,eAAO;AAAA,UACL,qBAAA,UAAA,EACE,UAAA;AAAA,YAAA,oBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,YAC/B,oBAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,KAAA,CAAK;AAAA,YACpC,oBAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,UAAA,EAAA,CACtC;AAAA,QAAA;AAAA,MAEJ,KAAK;AACH,eAAO;AAAA,UACL,qBAAA,UAAA,EACE,UAAA;AAAA,YAAA,oBAAC,QAAA,EAAK,GAAE,2FAAA,CAA2F;AAAA,YACnG,oBAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,YACrC,oBAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,KAAA,CAAK;AAAA,UAAA,EAAA,CAC3C;AAAA,QAAA;AAAA,MAEJ,KAAK;AAAA,MACL;AACE,eAAO;AAAA,UACL,qBAAA,UAAA,EACE,UAAA;AAAA,YAAA,oBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,YAC/B,oBAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,YACtC,oBAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,SAAQ,IAAG,IAAA,CAAI;AAAA,UAAA,EAAA,CACzC;AAAA,QAAA;AAAA,IACF;AAAA,EAEN;AAEA,SACE,qBAAC,SAAI,WAAW,gBAAgB,IAAI,IAAI,YAAY,mBAAmB,EAAE,IACtE,UAAA;AAAA,IAAA,QAAA;AAAA,IACD,oBAAC,QAAA,EAAK,WAAU,kBAAkB,UAAA,QAAA,CAAQ;AAAA,EAAA,GAC5C;AAEJ;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toaster Container Component
|
|
3
|
+
* Manages and displays multiple toast notifications
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import '../toaster.css';
|
|
7
|
+
export interface ToastState {
|
|
8
|
+
id: number;
|
|
9
|
+
message: string;
|
|
10
|
+
type: 'success' | 'error' | 'info' | 'warning';
|
|
11
|
+
duration?: number;
|
|
12
|
+
}
|
|
13
|
+
export interface ToasterProps {
|
|
14
|
+
toasts: ToastState[];
|
|
15
|
+
onDismiss: (id: number) => void;
|
|
16
|
+
position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
|
|
17
|
+
}
|
|
18
|
+
export declare function Toaster({ toasts, onDismiss, position }: ToasterProps): React.JSX.Element;
|
|
19
|
+
//# sourceMappingURL=Toaster.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../src/components/Toaster.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,gBAAgB,CAAA;AAEvB,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,QAAQ,CAAC,EACL,UAAU,GACV,YAAY,GACZ,WAAW,GACX,aAAa,GACb,eAAe,GACf,cAAc,CAAA;CACnB;AAED,wBAAgB,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAA0B,EAAE,EAAE,YAAY,qBActF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Toast } from "./Toast.js";
|
|
3
|
+
/* empty css */
|
|
4
|
+
function Toaster({ toasts, onDismiss, position = "bottom-center" }) {
|
|
5
|
+
return /* @__PURE__ */ jsx("div", { className: `toast-container toast-container--${position}`, children: toasts.map((toast) => /* @__PURE__ */ jsx(
|
|
6
|
+
Toast,
|
|
7
|
+
{
|
|
8
|
+
message: toast.message,
|
|
9
|
+
type: toast.type,
|
|
10
|
+
duration: toast.duration,
|
|
11
|
+
onClose: () => onDismiss(toast.id)
|
|
12
|
+
},
|
|
13
|
+
toast.id
|
|
14
|
+
)) });
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
Toaster
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=Toaster.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toaster.js","sources":["../../src/components/Toaster.tsx"],"sourcesContent":["/**\r\n * Toaster Container Component\r\n * Manages and displays multiple toast notifications\r\n */\r\n\r\nimport React from 'react'\r\nimport { Toast } from './Toast'\r\nimport '../toaster.css'\r\n\r\nexport interface ToastState {\r\n id: number\r\n message: string\r\n type: 'success' | 'error' | 'info' | 'warning'\r\n duration?: number\r\n}\r\n\r\nexport interface ToasterProps {\r\n toasts: ToastState[]\r\n onDismiss: (id: number) => void\r\n position?:\r\n | 'top-left'\r\n | 'top-center'\r\n | 'top-right'\r\n | 'bottom-left'\r\n | 'bottom-center'\r\n | 'bottom-right'\r\n}\r\n\r\nexport function Toaster({ toasts, onDismiss, position = 'bottom-center' }: ToasterProps) {\r\n return (\r\n <div className={`toast-container toast-container--${position}`}>\r\n {toasts.map(toast => (\r\n <Toast\r\n key={toast.id}\r\n message={toast.message}\r\n type={toast.type}\r\n duration={toast.duration}\r\n onClose={() => onDismiss(toast.id)}\r\n />\r\n ))}\r\n </div>\r\n )\r\n}\r\n"],"names":[],"mappings":";;;AA4BO,SAAS,QAAQ,EAAE,QAAQ,WAAW,WAAW,mBAAiC;AACvF,SACE,oBAAC,SAAI,WAAW,oCAAoC,QAAQ,IACzD,UAAA,OAAO,IAAI,CAAA,UACV;AAAA,IAAC;AAAA,IAAA;AAAA,MAEC,SAAS,MAAM;AAAA,MACf,MAAM,MAAM;AAAA,MACZ,UAAU,MAAM;AAAA,MAChB,SAAS,MAAM,UAAU,MAAM,EAAE;AAAA,IAAA;AAAA,IAJ5B,MAAM;AAAA,EAAA,CAMd,GACH;AAEJ;"}
|