@modalogue/core 0.1.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.
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # @modalogue/core
2
+
3
+ Headless state management for multi-step dialogs. Framework-agnostic with zero dependencies.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @modalogue/core
9
+ # or
10
+ pnpm add @modalogue/core
11
+ # or
12
+ yarn add @modalogue/core
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```typescript
18
+ import Modalogue from '@modalogue/core';
19
+
20
+ // Create a new instance
21
+ const modalogue = new Modalogue();
22
+
23
+ // Subscribe to state changes
24
+ const unsubscribe = modalogue.subscribe((state) => {
25
+ console.log('Modal state:', state);
26
+ // state.isOpen - boolean
27
+ // state.activeView - { id, element }
28
+ // state.hasHistory - boolean
29
+ });
30
+
31
+ // Open a modal with content
32
+ modalogue.open(<YourContent />);
33
+
34
+ // Navigate to a new view (adds to history)
35
+ modalogue.navigate(<NextView />);
36
+
37
+ // Go back to previous view
38
+ modalogue.back();
39
+
40
+ // Close modal and clear history
41
+ modalogue.close();
42
+
43
+ // Hide modal without clearing history
44
+ modalogue.hide();
45
+
46
+ // Show hidden modal
47
+ modalogue.show();
48
+
49
+ // Clean up subscription
50
+ unsubscribe();
51
+ ```
52
+
53
+ ## API
54
+
55
+ ### `new Modalogue()`
56
+
57
+ Creates a new Modalogue instance.
58
+
59
+ ### `modalogue.subscribe(callback): () => void`
60
+
61
+ Subscribe to state changes. Returns an unsubscribe function.
62
+
63
+ ### `modalogue.open(content): void`
64
+
65
+ Opens the modal with the given content. Clears any existing history.
66
+
67
+ ### `modalogue.navigate(content): void`
68
+
69
+ Navigates to new content, preserving history for back navigation.
70
+
71
+ ### `modalogue.back(): void`
72
+
73
+ Goes back to the previous view. If on the first view, closes the modal.
74
+
75
+ ### `modalogue.close(): void`
76
+
77
+ Closes the modal and clears all history.
78
+
79
+ ### `modalogue.hide(): void`
80
+
81
+ Hides the modal without clearing history (can be shown again).
82
+
83
+ ### `modalogue.show(): void`
84
+
85
+ Shows a previously hidden modal.
86
+
87
+ ## Types
88
+
89
+ ```typescript
90
+ import type { ModalState, ModalContent, ActiveView, Subscriber, ModalAPI } from '@modalogue/core';
91
+ ```
92
+
93
+ ## License
94
+
95
+ MIT
@@ -0,0 +1,39 @@
1
+ type ModalContent<T = any> = T;
2
+ type ActiveView = {
3
+ element: ModalContent | null;
4
+ id: number | null;
5
+ };
6
+ type ModalState = {
7
+ isOpen: boolean;
8
+ activeView: ActiveView;
9
+ hasHistory: boolean;
10
+ };
11
+ type Subscriber = (state: ModalState) => void;
12
+ interface ModalAPI {
13
+ open: (content: ModalContent) => void;
14
+ navigate: (content: ModalContent) => void;
15
+ back: () => void;
16
+ close: () => void;
17
+ hide: () => void;
18
+ show: () => void;
19
+ subscribe: (callback: Subscriber) => () => void;
20
+ }
21
+
22
+ declare class Modalogue {
23
+ private subscribers;
24
+ private isOpen;
25
+ private viewHistory;
26
+ constructor();
27
+ subscribe: (callback: Subscriber) => (() => void);
28
+ private notify;
29
+ private getActiveView;
30
+ open: (content: ModalContent) => void;
31
+ navigate: (content: ModalContent) => void;
32
+ back: () => void;
33
+ close: () => void;
34
+ hide: () => void;
35
+ show: () => void;
36
+ }
37
+
38
+ export { Modalogue as default };
39
+ export type { ActiveView, ModalAPI, ModalContent, ModalState, Subscriber };
@@ -0,0 +1,39 @@
1
+ type ModalContent<T = any> = T;
2
+ type ActiveView = {
3
+ element: ModalContent | null;
4
+ id: number | null;
5
+ };
6
+ type ModalState = {
7
+ isOpen: boolean;
8
+ activeView: ActiveView;
9
+ hasHistory: boolean;
10
+ };
11
+ type Subscriber = (state: ModalState) => void;
12
+ interface ModalAPI {
13
+ open: (content: ModalContent) => void;
14
+ navigate: (content: ModalContent) => void;
15
+ back: () => void;
16
+ close: () => void;
17
+ hide: () => void;
18
+ show: () => void;
19
+ subscribe: (callback: Subscriber) => () => void;
20
+ }
21
+
22
+ declare class Modalogue {
23
+ private subscribers;
24
+ private isOpen;
25
+ private viewHistory;
26
+ constructor();
27
+ subscribe: (callback: Subscriber) => (() => void);
28
+ private notify;
29
+ private getActiveView;
30
+ open: (content: ModalContent) => void;
31
+ navigate: (content: ModalContent) => void;
32
+ back: () => void;
33
+ close: () => void;
34
+ hide: () => void;
35
+ show: () => void;
36
+ }
37
+
38
+ export { Modalogue as default };
39
+ export type { ActiveView, ModalAPI, ModalContent, ModalState, Subscriber };
package/dist/index.js ADDED
@@ -0,0 +1,70 @@
1
+ Object.defineProperty(exports, '__esModule', { value: true });
2
+
3
+ class Modalogue {
4
+ constructor(){
5
+ this.subscribers = new Set();
6
+ this.isOpen = false;
7
+ this.viewHistory = [];
8
+ this.subscribe = (callback)=>{
9
+ this.subscribers.add(callback);
10
+ return ()=>this.subscribers.delete(callback);
11
+ };
12
+ this.notify = ()=>{
13
+ const state = {
14
+ isOpen: this.isOpen,
15
+ activeView: this.getActiveView(),
16
+ hasHistory: this.viewHistory.length > 1
17
+ };
18
+ this.subscribers.forEach((subscriber)=>subscriber(state));
19
+ };
20
+ this.getActiveView = ()=>{
21
+ return this.viewHistory[this.viewHistory.length - 1] || {
22
+ id: null,
23
+ element: null
24
+ };
25
+ };
26
+ this.open = (content)=>{
27
+ this.viewHistory = [
28
+ {
29
+ id: 0,
30
+ element: content
31
+ }
32
+ ];
33
+ this.isOpen = true;
34
+ this.notify();
35
+ };
36
+ this.navigate = (content)=>{
37
+ this.viewHistory.push({
38
+ id: this.viewHistory.length,
39
+ element: content
40
+ });
41
+ this.notify();
42
+ };
43
+ this.back = ()=>{
44
+ if (this.viewHistory.length > 1) {
45
+ this.viewHistory.pop();
46
+ this.notify();
47
+ } else {
48
+ this.close();
49
+ }
50
+ };
51
+ this.close = ()=>{
52
+ this.isOpen = false;
53
+ this.viewHistory = [];
54
+ this.notify();
55
+ };
56
+ this.hide = ()=>{
57
+ this.isOpen = false;
58
+ this.notify();
59
+ };
60
+ this.show = ()=>{
61
+ this.isOpen = true;
62
+ this.notify();
63
+ };
64
+ // if (!Modalogue.instance) {
65
+ // Modalogue.instance = new Modalogue();
66
+ // }
67
+ }
68
+ }
69
+
70
+ exports.default = Modalogue;
package/dist/index.mjs ADDED
@@ -0,0 +1,68 @@
1
+ class Modalogue {
2
+ constructor(){
3
+ this.subscribers = new Set();
4
+ this.isOpen = false;
5
+ this.viewHistory = [];
6
+ this.subscribe = (callback)=>{
7
+ this.subscribers.add(callback);
8
+ return ()=>this.subscribers.delete(callback);
9
+ };
10
+ this.notify = ()=>{
11
+ const state = {
12
+ isOpen: this.isOpen,
13
+ activeView: this.getActiveView(),
14
+ hasHistory: this.viewHistory.length > 1
15
+ };
16
+ this.subscribers.forEach((subscriber)=>subscriber(state));
17
+ };
18
+ this.getActiveView = ()=>{
19
+ return this.viewHistory[this.viewHistory.length - 1] || {
20
+ id: null,
21
+ element: null
22
+ };
23
+ };
24
+ this.open = (content)=>{
25
+ this.viewHistory = [
26
+ {
27
+ id: 0,
28
+ element: content
29
+ }
30
+ ];
31
+ this.isOpen = true;
32
+ this.notify();
33
+ };
34
+ this.navigate = (content)=>{
35
+ this.viewHistory.push({
36
+ id: this.viewHistory.length,
37
+ element: content
38
+ });
39
+ this.notify();
40
+ };
41
+ this.back = ()=>{
42
+ if (this.viewHistory.length > 1) {
43
+ this.viewHistory.pop();
44
+ this.notify();
45
+ } else {
46
+ this.close();
47
+ }
48
+ };
49
+ this.close = ()=>{
50
+ this.isOpen = false;
51
+ this.viewHistory = [];
52
+ this.notify();
53
+ };
54
+ this.hide = ()=>{
55
+ this.isOpen = false;
56
+ this.notify();
57
+ };
58
+ this.show = ()=>{
59
+ this.isOpen = true;
60
+ this.notify();
61
+ };
62
+ // if (!Modalogue.instance) {
63
+ // Modalogue.instance = new Modalogue();
64
+ // }
65
+ }
66
+ }
67
+
68
+ export { Modalogue as default };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@modalogue/core",
3
+ "version": "0.1.0",
4
+ "description": "Headless state management for multi-step dialogs",
5
+ "exports": {
6
+ ".": {
7
+ "import": {
8
+ "types": "./dist/index.d.mts",
9
+ "default": "./dist/index.mjs"
10
+ },
11
+ "require": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ }
15
+ }
16
+ },
17
+ "main": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "sideEffects": false,
23
+ "scripts": {
24
+ "build": "bunchee",
25
+ "dev": "bunchee --watch",
26
+ "type-check": "tsc --noEmit",
27
+ "test:unit": "vitest",
28
+ "test:unit:run": "vitest run",
29
+ "test:unit:coverage": "vitest run --coverage"
30
+ },
31
+ "keywords": [
32
+ "modal",
33
+ "dialog",
34
+ "multi-step",
35
+ "headless",
36
+ "state-management"
37
+ ],
38
+ "author": "Edoardo Guido <ciao@edoardoguido.com>",
39
+ "license": "MIT",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/edoardoguido/modalogue",
43
+ "directory": "packages/core"
44
+ },
45
+ "homepage": "https://modalogue.dev",
46
+ "peerDependencies": {},
47
+ "dependencies": {},
48
+ "devDependencies": {
49
+ "@testing-library/jest-dom": "^6.6.3",
50
+ "bunchee": "^6.5.2",
51
+ "jsdom": "^26.1.0",
52
+ "typescript": "^5.8.3",
53
+ "vitest": "^2.1.8"
54
+ }
55
+ }