frutjam 0.0.1 → 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2024 Nezanuha
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1 +1,79 @@
1
- # Welcome to Frutjam
1
+ # Frutjam Useful Prebuilt Plugins & UI Components for TailwindCSS
2
+
3
+ Frutjam is a powerful library with an array of useful plugins and UI components created exclusively for use with Tailwind CSS. Whether you're creating a web app, a website, or a digital product, Frutjam offers a variety of tools to help you boost your development process and improve user experience. Furthermore, it provides numerous customization options within its plugins, allowing you to design your solutions precisely to your requirements.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Usage](#usage)
9
+ - [License](#license)
10
+
11
+ ## Documentations
12
+ For detail documentation, visit [frutjam.com](https://frutjam.com)
13
+
14
+ ## Key Features:
15
+
16
+ 1. **Tailwind CSS Integration:** Frutjam is designed to work easily with Tailwind CSS, a well-known utility-focused CSS framework. This integration allows you to use the full power of Tailwind's utility classes while also benefiting from Frutjam's additional features.
17
+
18
+ 2. **Useful Plugins:** Frutjam is releasing a number of plugins that will enhance your projects' functionality. These plugins include features like notifications, modals, sliders, form elements, and more. Each plugin is intended to be simple to use, adaptable, and compatible with current web development methods.
19
+
20
+ 3. **UI Components:** In addition to plugins, Frutjam provides an extensive collection of UI components that can be simply integrated into your projects. From navigation menus and cards to buttons and input fields, these components are designed to be accessible, responsive, and visually appealing.
21
+
22
+ 4. **Framework & Libraries Support:** Written in TypeScript, Frutjam supports CommonJS (CJS) and ECMAScript Modules (ESM). It is being developed to support new web frameworks and libraries, such as React, Next.js, Vue, and others.
23
+
24
+ 5. **MIT License:** Frutjam is released under the MIT License, allowing you the freedom to use, alter, and distribute the library as needed for both commercial and personal projects.
25
+
26
+ Whether you're a beginner exploring web development or an experienced developer looking for efficient tools, Frutjam offers a versatile set of resources to streamline your projects and elevate the user experience.
27
+
28
+ ## Getting started
29
+
30
+ Whether you're a newbie exploring web development or an experienced developer seeking for efficient tools, Frutjam provides a diverse variety of resources to help you streamline your projects and improve the user experience.
31
+
32
+ ## Installation
33
+
34
+ You can install Frutjam via npm:
35
+
36
+ ```bash
37
+ npm install frutjam
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ Import the `Notification` class from Frutjam:
43
+
44
+ ```typescript
45
+ import { Notification } from "frutjam";
46
+ import "frutjam/dist/notification.css";
47
+ ```
48
+
49
+ Create a new notification instance with custom configurations:
50
+
51
+ ```typescript
52
+ new Notification({
53
+ effect: "slide",
54
+ escapeTime: 5000,
55
+ autoClose: false,
56
+ arriveFrom: "top",
57
+ element: "<div class='your-customizable-design-class'><button type='button' data-fj='toggle-btn'>Close</button><!-- Add your other elements here --></div>"
58
+ });
59
+ ```
60
+
61
+ ### Configuration Options
62
+
63
+ - `effect`: Choose between "fade" or "slide" for the notification effect.
64
+ - `escapeTime`: Time in milliseconds before the notification automatically closes.
65
+ - `arriveTime`: specifies the time in milliseconds after which the notification's arrival animation completes.
66
+ - `autoClose`: Boolean to enable or disable automatic closing of the notification.
67
+ - `arriveFrom`: Direction from which the notification should arrive ("left", "right", "top", "bottom").
68
+ - `element`: Customise your own HTML element to be displayed in the notification.
69
+
70
+ `<button type='button' data-fj='toggle-btn'>Close</button>`
71
+ To enable manual closing of the current element, set the `data-fj='toggle-btn'` attribute to button.
72
+
73
+ ## License
74
+
75
+ Frutjam is Open Source project licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
76
+
77
+ ## Support
78
+
79
+ For any questions or issues, please [open an issue](https://github.com/nezanuha/frutjam/issues) on GitHub.
package/package.json CHANGED
@@ -1,34 +1,37 @@
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.3",
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
+ "postcss": "^8.4.38",
33
+ "tailwindcss": "^3.4.3",
34
+ "tsup": "^8.0.2",
35
+ "typescript": "^5.4.5"
36
+ }
37
+ }
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 2024 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,22 @@
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;
8
9
  element?: HTMLElement | null;
10
+ }
11
+
12
+ export interface NotificationConfig {
13
+ arriveFrom: {
14
+ right: string;
15
+ left: string;
16
+ bottom: string;
17
+ top: string;
18
+ };
19
+ effects: {
20
+ [key: string]: string;
21
+ };
9
22
  }
@@ -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
+ }