frutjam 0.0.1 → 0.0.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/package.json CHANGED
@@ -1,34 +1,38 @@
1
- {
2
- "name": "frutjam",
3
- "version": "0.0.1",
4
- "description": "Frutjam includes prebuilt UI components and plugins that are completely open-source",
5
- "main": "./dist/index.js",
6
- "module": "./dist/index.mjs",
7
- "types": "./dist/index.d.ts",
8
- "repository": {
9
- "type": "github",
10
- "url": "git+https://github.com/nezanuha/frutjam.git"
11
- },
12
- "scripts": {
13
- "build": "tsup",
14
- "test": "echo \"Error: no test specified\" && exit 1"
15
- },
16
- "keywords": [
17
- "frutjam",
18
- "Nezanuha"
19
- ],
20
- "author": "Nezanuha",
21
- "license": "MIT",
22
- "homepage": "https://frutjam.com",
23
- "bugs": {
24
- "url": "https://github.com/nezanuha/frutjam/issues"
25
- },
26
- "files": [
27
- "src/**/*"
28
- ],
29
- "devDependencies": {
30
- "esbuild": "^0.20.2",
31
- "tsup": "^8.0.2",
32
- "typescript": "^5.4.5"
33
- }
34
- }
1
+ {
2
+ "name": "frutjam",
3
+ "version": "0.0.2",
4
+ "description": "Frutjam includes prebuilt UI components and plugins that are completely open-source",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "repository": {
9
+ "type": "github",
10
+ "url": "git+https://github.com/nezanuha/frutjam.git"
11
+ },
12
+ "scripts": {
13
+ "dev": "tsup --watch",
14
+ "build": "tsup",
15
+ "test": "echo \"Error: no test specified\" && exit 1"
16
+ },
17
+ "keywords": [
18
+ "frutjam",
19
+ "Nezanuha"
20
+ ],
21
+ "author": "Nezanuha",
22
+ "license": "MIT",
23
+ "homepage": "https://frutjam.com",
24
+ "bugs": {
25
+ "url": "https://github.com/nezanuha/frutjam/issues"
26
+ },
27
+ "files": [
28
+ "src/**/*"
29
+ ],
30
+ "devDependencies": {
31
+ "autoprefixer": "^10.4.19",
32
+ "esbuild": "^0.20.2",
33
+ "postcss": "^8.4.38",
34
+ "tailwindcss": "^3.4.3",
35
+ "tsup": "^8.0.2",
36
+ "typescript": "^5.4.5"
37
+ }
38
+ }
package/src/index.ts CHANGED
@@ -1 +1,3 @@
1
- export { default as Notification } from './plugins/notification'
1
+ export { default as Notification } from './plugins/notification'
2
+ // export { default as TelephoneInput } from './plugins/telephoneInput'
3
+ // export { default as Popover } from './plugins/popover'
@@ -0,0 +1,14 @@
1
+ import { NotificationConfig } from "./interfaces";
2
+
3
+ export const config: NotificationConfig = {
4
+ arriveFrom: {
5
+ right: 'translate-x-full',
6
+ left: '-translate-x-full',
7
+ bottom: 'translate-y-full',
8
+ top: '-translate-y-full',
9
+ },
10
+ effects: {
11
+ slide: 'duration-300',
12
+ fade: 'opacity-0 duration-300',
13
+ },
14
+ };
@@ -1,74 +1,124 @@
1
+ /*
2
+ * Notification
3
+ * @version: 0.0.2
4
+ * @author: Nezanuha
5
+ * @license: Licensed under MIT
6
+ * Copyright 2023 Nezanuha
7
+ */
8
+
1
9
  import { NotificationOptions } from './interfaces';
2
- import { TimeoutId } from './types';
10
+ import type { ArriveFrom, TimeoutId } from './types';
11
+ import "./styles.css"
12
+ import { config } from './config';
3
13
 
4
14
  export default class Notification {
5
15
  effect: string;
6
16
  escapeTime: number;
7
17
  arriveTime: number;
8
18
  autoClose: boolean;
19
+ arriveFrom: ArriveFrom;
9
20
  element: HTMLElement | null;
10
21
  timeoutId: TimeoutId;
11
22
 
12
- constructor({ effect = 'fade', escapeTime = 3000, arriveTime = 200, autoClose = true, element = null }: NotificationOptions = {}) {
23
+ constructor({ effect = 'fade', escapeTime = 3000, arriveTime = 200, autoClose = true, arriveFrom = 'right', element = null }: NotificationOptions = {}) {
13
24
  this.effect = effect;
14
25
  this.arriveTime = arriveTime;
15
26
  this.autoClose = autoClose;
27
+ this.arriveFrom = arriveFrom;
16
28
  this.escapeTime = escapeTime;
17
29
  this.element = element;
18
30
  this.timeoutId = null; // Initialize timeout ID as null
19
31
  this.render();
20
- this.action();
32
+ this.init();
21
33
  }
22
34
 
23
35
  render() {
24
- if (this.element) {
25
- document.querySelector("body")?.insertAdjacentElement('beforeend', this.element);
36
+ if (typeof this.element === 'string') {
37
+ const tempDiv = document.createElement('div');
38
+ tempDiv.innerHTML = this.element;
39
+ this.element = tempDiv.firstChild as HTMLElement;
40
+ this.element.setAttribute("data-fj", "user-element");
26
41
  }
27
- }
42
+
43
+ // Inside the render method of the Notification class
44
+ if (this.element instanceof HTMLElement) {
45
+ let container = document.querySelector<HTMLElement>("[data-fj='notification']");
46
+ if (!container) {
47
+ container = document.createElement('div');
48
+ container.setAttribute('data-fj', 'notification');
49
+ document.querySelector("body")?.insertAdjacentElement('beforeend', container);
50
+ }
28
51
 
29
- action() {
30
- document.querySelectorAll("[data-fj='toggle-btn']").forEach((event) => {
31
- event.addEventListener("click", (e) => {
32
- const self = e.target as HTMLElement;
33
- const container = self.closest<HTMLElement>("[data-fj='notification']");
34
- if (container) {
35
- this.toggleNotification(container);
36
- }
52
+ // Check if the element being appended is not the same as the container itself
53
+ if (this.element !== container) {
54
+ container.appendChild(this.element);
55
+ }
37
56
 
38
- // Clear the timeout when the click event occurs
39
- if (this.timeoutId !== null) {
40
- clearTimeout(this.timeoutId);
41
- this.timeoutId = null;
42
- }
43
- });
44
- });
45
57
 
46
- // Set the timeout to toggle the class after arriveTime
58
+ if (this.effect == 'slide') {
59
+ const arriveFromClass = config.arriveFrom[this.arriveFrom];
60
+ this.element.classList.add(arriveFromClass, 'duration-300');
61
+ } else {
62
+ this.element.classList.add('opacity-0', 'duration-300');
63
+ }
64
+ } else {
65
+ console.error("No element provided. Element must be either an HTMLElement or a string representing raw HTML.");
66
+ }
67
+
68
+
47
69
  this.timeoutId = setTimeout(() => {
48
- const notificationsContainer = document.querySelectorAll<HTMLElement>("[data-fj='notification']");
49
- notificationsContainer.forEach((container) => {
50
- this.toggleNotification(container);
51
- });
52
- this.timeoutId = null; // Reset timeout ID after it's triggered
70
+ this.toggleNotification(this.element); // Pass the current element to toggleNotification
71
+ this.timeoutId = null;
53
72
  }, this.arriveTime);
54
-
73
+
55
74
  if (this.autoClose === true) {
56
75
  this.timeoutId = setTimeout(() => {
57
- const notificationsContainer = document.querySelectorAll<HTMLElement>("[data-fj='notification']");
58
- notificationsContainer.forEach((container) => {
59
- this.toggleNotification(container);
60
- });
61
- this.timeoutId = null; // Reset timeout ID after it's triggered
76
+ this.toggleNotification(this.element, 'close'); // Pass the current element to toggleNotification
77
+ this.timeoutId = null;
62
78
  }, this.escapeTime);
63
79
  }
64
80
  }
65
81
 
66
- toggleNotification(container: HTMLElement) {
67
- if (this.effect == 'slide') {
68
- container.classList.toggle("translate-x-0");
82
+ init() {
83
+ const handleClick = (e: MouseEvent) => {
84
+ const self = e.target as HTMLElement;
85
+ const userElement = self.closest<HTMLElement>("[data-fj='user-element']");
86
+ if (userElement) {
87
+ this.toggleNotification(userElement, 'close');
88
+ }
89
+
90
+ if (this.timeoutId !== null) {
91
+ clearTimeout(this.timeoutId);
92
+ this.timeoutId = null;
93
+ }
94
+ };
95
+
96
+ // Add event listeners only once for all toggle buttons
97
+ const toggleButtons = document.querySelectorAll<HTMLElement>("[data-fj='toggle-btn']");
98
+ toggleButtons.forEach(button => {
99
+ // Check if the event listener is already added before adding it again
100
+ if (!button.dataset.clickEventAdded) {
101
+ button.dataset.clickEventAdded = "true"; // Set a flag to indicate that the event listener is added
102
+ button.addEventListener("click", handleClick);
103
+ }
104
+ });
105
+ }
106
+
107
+ toggleNotification(container: HTMLElement | null, type?: string) {
108
+ if (container instanceof HTMLElement) {
109
+ if (this.effect == 'slide') {
110
+ const arriveFromClass = config.arriveFrom[this.arriveFrom];
111
+ container.classList.toggle(arriveFromClass, !container.classList.contains(arriveFromClass));
112
+ } else {
113
+ container.classList.toggle("opacity-0", !container.classList.contains("opacity-0"));
114
+ }
115
+ if (type === 'close') {
116
+ setTimeout(() => {
117
+ container.remove();
118
+ }, 300);
119
+ }
69
120
  } else {
70
- container.classList.toggle("opacity-100");
121
+ console.error("Container is null or not an HTMLElement.");
71
122
  }
72
- // Add other toggle logic here if needed
73
- }
123
+ }
74
124
  }
@@ -1,9 +1,23 @@
1
- import { TimeoutId } from './types';
1
+ import type { ArriveFrom, TimeoutId } from './types';
2
2
 
3
3
  export interface NotificationOptions {
4
4
  effect?: string;
5
5
  escapeTime?: number;
6
6
  arriveTime?: number;
7
7
  autoClose?: boolean;
8
+ arriveFrom?: ArriveFrom; // Use the ArriveFrom type here
8
9
  element?: HTMLElement | null;
10
+ }
11
+
12
+ // Define your Config interface or type with index signature for effects
13
+ export interface NotificationConfig {
14
+ arriveFrom: {
15
+ right: string;
16
+ left: string;
17
+ bottom: string;
18
+ top: string;
19
+ };
20
+ effects: {
21
+ [key: string]: string; // Index signature for effects
22
+ };
9
23
  }
@@ -0,0 +1,9 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @layer utilities{
6
+ [data-fj='notification'] {
7
+ @apply overflow-hidden m-6 max-h-max
8
+ }
9
+ }
@@ -1 +1,5 @@
1
- export type TimeoutId = ReturnType<typeof setTimeout> | null;
1
+ type ArriveFrom = 'right' | 'left' | 'bottom' | 'top';
2
+
3
+ type TimeoutId = ReturnType<typeof setTimeout> | null;
4
+
5
+ export type { ArriveFrom, TimeoutId }
@@ -0,0 +1,45 @@
1
+ import "./styles.css"
2
+ export default class Popover {
3
+ autoPopup: boolean;
4
+ popupTime: number;
5
+ timeoutId: number | null;
6
+
7
+ constructor({ autoPopup = false, popupTime = 2000 }: { autoPopup?: boolean; popupTime?: number } = {}) {
8
+ this.autoPopup = autoPopup;
9
+ this.popupTime = popupTime;
10
+ this.timeoutId = null;
11
+ this.action();
12
+ }
13
+
14
+ action(): void {
15
+ document.querySelectorAll<HTMLElement>(".fj-popover-toggle").forEach((event) => {
16
+ event.addEventListener("click", (e) => {
17
+ const self = e.target as HTMLElement;
18
+ const popoverContent = self.closest(".fj-popover")!.querySelector(".fj-popover-content") as HTMLElement | null;
19
+ if (popoverContent) {
20
+ this.togglePopover(popoverContent);
21
+ }
22
+
23
+ if (this.timeoutId !== null) {
24
+ clearTimeout(this.timeoutId);
25
+ this.timeoutId = null;
26
+ }
27
+ });
28
+ });
29
+
30
+ if (this.autoPopup === true) {
31
+ this.timeoutId = window.setTimeout(() => {
32
+ const popoverContents = document.querySelectorAll<HTMLElement>(".fj-popover .fj-popover-content");
33
+ popoverContents.forEach((popoverContent) => {
34
+ this.togglePopover(popoverContent);
35
+ });
36
+ this.timeoutId = null;
37
+ }, this.popupTime);
38
+ }
39
+ }
40
+
41
+ togglePopover(popoverContent: HTMLElement): void {
42
+ popoverContent.classList.toggle("translate-y-0");
43
+ // Add other toggle logic here if needed
44
+ }
45
+ }
@@ -0,0 +1,12 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @layer utilities{
6
+ .fj-popover{
7
+ @apply flex flex-col gap-3 justify-end items-end
8
+ }
9
+ .fj-popover-content{
10
+ @apply max-w-lg w-full z-50 translate-y-[40rem] duration-300
11
+ }
12
+ }