@mshafiqyajid/react-modal 0.0.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.
@@ -0,0 +1,247 @@
1
+ /* ============================================================================
2
+ * react-modal — styled component
3
+ *
4
+ * Dark mode: [data-theme="dark"] on any ancestor — never prefers-color-scheme.
5
+ * ========================================================================== */
6
+
7
+ .rmod-overlay {
8
+ --rmod-fg: #18181b;
9
+ --rmod-fg-muted: #71717a;
10
+ --rmod-bg: #ffffff;
11
+ --rmod-bg-header: #fafafa;
12
+ --rmod-bg-footer: #fafafa;
13
+ --rmod-border: #e4e4e7;
14
+ --rmod-overlay-bg: rgba(0, 0, 0, 0.45);
15
+ --rmod-shadow: 0 24px 64px rgba(0,0,0,0.14), 0 4px 16px rgba(0,0,0,0.08);
16
+ --rmod-radius: 14px;
17
+ --rmod-close-bg-hover: #f4f4f5;
18
+ --rmod-close-fg: #71717a;
19
+ --rmod-close-fg-hover: #18181b;
20
+ --rmod-duration: 220ms;
21
+ --rmod-ease: cubic-bezier(0.32, 0.72, 0, 1);
22
+ --rmod-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
23
+
24
+ position: fixed;
25
+ inset: 0;
26
+ z-index: 9000;
27
+ display: flex;
28
+ align-items: center;
29
+ justify-content: center;
30
+ padding: 1rem;
31
+ background: var(--rmod-overlay-bg);
32
+
33
+ /* Backdrop blur — default md */
34
+ backdrop-filter: blur(8px);
35
+ -webkit-backdrop-filter: blur(8px);
36
+
37
+ opacity: 0;
38
+ transition: opacity var(--rmod-duration) var(--rmod-ease),
39
+ backdrop-filter var(--rmod-duration) var(--rmod-ease);
40
+ pointer-events: none;
41
+ }
42
+
43
+ .rmod-overlay--visible {
44
+ opacity: 1;
45
+ pointer-events: auto;
46
+ }
47
+
48
+ /* Blur variants */
49
+ .rmod-overlay[data-blur="none"] { backdrop-filter: none; -webkit-backdrop-filter: none; }
50
+ .rmod-overlay[data-blur="sm"] { backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
51
+ .rmod-overlay[data-blur="md"] { backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
52
+ .rmod-overlay[data-blur="lg"] { backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); }
53
+
54
+ /* Drawer alignment */
55
+ .rmod-overlay[data-variant="drawer-left"] { justify-content: flex-start; padding: 0; }
56
+ .rmod-overlay[data-variant="drawer-right"] { justify-content: flex-end; padding: 0; }
57
+ .rmod-overlay[data-variant="drawer-bottom"] { align-items: flex-end; padding: 0; }
58
+
59
+ /* ============================================================================
60
+ * Panel — base (dialog only)
61
+ * ========================================================================== */
62
+ .rmod-panel {
63
+ position: relative;
64
+ display: flex;
65
+ flex-direction: column;
66
+ background: var(--rmod-bg);
67
+ border-radius: var(--rmod-radius);
68
+ box-shadow: var(--rmod-shadow);
69
+ max-height: calc(100vh - 2rem);
70
+ width: 100%;
71
+ overflow: hidden;
72
+ outline: none;
73
+ }
74
+
75
+ /* Dialog enter/exit */
76
+ .rmod-panel[data-variant="dialog"] {
77
+ opacity: 0;
78
+ transform: scale(0.94) translateY(8px);
79
+ transition:
80
+ opacity var(--rmod-duration) var(--rmod-ease),
81
+ transform var(--rmod-duration) var(--rmod-ease-spring);
82
+ }
83
+ .rmod-panel[data-variant="dialog"].rmod-panel--visible {
84
+ opacity: 1;
85
+ transform: scale(1) translateY(0);
86
+ }
87
+
88
+ /* Panel sizes */
89
+ .rmod-panel[data-size="sm"][data-variant="dialog"] { max-width: 400px; }
90
+ .rmod-panel[data-size="md"][data-variant="dialog"] { max-width: 560px; }
91
+ .rmod-panel[data-size="lg"][data-variant="dialog"] { max-width: 800px; }
92
+ .rmod-panel[data-size="full"][data-variant="dialog"] { max-width: calc(100vw - 2rem); max-height: calc(100vh - 2rem); }
93
+
94
+ /* ============================================================================
95
+ * Drawer — left
96
+ * ========================================================================== */
97
+ .rmod-panel[data-variant="drawer-left"] {
98
+ height: 100vh; max-height: 100vh;
99
+ border-radius: 0 var(--rmod-radius) var(--rmod-radius) 0;
100
+ opacity: 1;
101
+ transform: translateX(-100%);
102
+ transition: transform var(--rmod-duration) var(--rmod-ease);
103
+ }
104
+ .rmod-panel[data-variant="drawer-left"].rmod-panel--visible { transform: translateX(0); }
105
+ .rmod-panel[data-size="sm"][data-variant="drawer-left"] { max-width: 280px; }
106
+ .rmod-panel[data-size="md"][data-variant="drawer-left"] { max-width: 380px; }
107
+ .rmod-panel[data-size="lg"][data-variant="drawer-left"] { max-width: 520px; }
108
+ .rmod-panel[data-size="full"][data-variant="drawer-left"] { max-width: 100vw; border-radius: 0; }
109
+
110
+ /* ============================================================================
111
+ * Drawer — right
112
+ * ========================================================================== */
113
+ .rmod-panel[data-variant="drawer-right"] {
114
+ height: 100vh; max-height: 100vh;
115
+ border-radius: var(--rmod-radius) 0 0 var(--rmod-radius);
116
+ opacity: 1;
117
+ transform: translateX(100%);
118
+ transition: transform var(--rmod-duration) var(--rmod-ease);
119
+ }
120
+ .rmod-panel[data-variant="drawer-right"].rmod-panel--visible { transform: translateX(0); }
121
+ .rmod-panel[data-size="sm"][data-variant="drawer-right"] { max-width: 280px; }
122
+ .rmod-panel[data-size="md"][data-variant="drawer-right"] { max-width: 380px; }
123
+ .rmod-panel[data-size="lg"][data-variant="drawer-right"] { max-width: 520px; }
124
+ .rmod-panel[data-size="full"][data-variant="drawer-right"] { max-width: 100vw; border-radius: 0; }
125
+
126
+ /* ============================================================================
127
+ * Drawer — bottom
128
+ * ========================================================================== */
129
+ .rmod-panel[data-variant="drawer-bottom"] {
130
+ width: 100%; max-width: 100%; max-height: 80vh;
131
+ border-radius: var(--rmod-radius) var(--rmod-radius) 0 0;
132
+ opacity: 1;
133
+ transform: translateY(100%);
134
+ transition: transform var(--rmod-duration) var(--rmod-ease);
135
+ }
136
+ .rmod-panel[data-variant="drawer-bottom"].rmod-panel--visible { transform: translateY(0); }
137
+
138
+ /* Drag handle for bottom drawer */
139
+ .rmod-panel[data-variant="drawer-bottom"] .rmod-header::before {
140
+ content: "";
141
+ display: block;
142
+ width: 36px; height: 4px;
143
+ background: var(--rmod-border);
144
+ border-radius: 2px;
145
+ margin: 0 auto 0.75rem;
146
+ order: -1;
147
+ flex-basis: 100%;
148
+ }
149
+ .rmod-panel[data-variant="drawer-bottom"] .rmod-header {
150
+ flex-wrap: wrap;
151
+ }
152
+
153
+ /* ============================================================================
154
+ * Header
155
+ * ========================================================================== */
156
+ .rmod-header {
157
+ display: flex;
158
+ align-items: center;
159
+ justify-content: space-between;
160
+ gap: 0.75rem;
161
+ padding: 1rem 1.25rem;
162
+ background: var(--rmod-bg-header);
163
+ border-bottom: 1px solid var(--rmod-border);
164
+ flex-shrink: 0;
165
+ }
166
+
167
+ .rmod-title {
168
+ margin: 0;
169
+ font-size: 1rem;
170
+ font-weight: 600;
171
+ color: var(--rmod-fg);
172
+ line-height: 1.4;
173
+ flex: 1;
174
+ }
175
+
176
+ /* ============================================================================
177
+ * Close button
178
+ * ========================================================================== */
179
+ .rmod-close {
180
+ display: flex; align-items: center; justify-content: center;
181
+ flex-shrink: 0;
182
+ width: 2rem; height: 2rem;
183
+ padding: 0; border: none; border-radius: 6px;
184
+ background: transparent;
185
+ color: var(--rmod-close-fg);
186
+ cursor: pointer;
187
+ transition: background-color 150ms ease, color 150ms ease;
188
+ }
189
+ .rmod-close:hover { background: var(--rmod-close-bg-hover); color: var(--rmod-close-fg-hover); }
190
+ .rmod-close:focus-visible { outline: 2px solid currentColor; outline-offset: 1px; }
191
+
192
+ /* ============================================================================
193
+ * Body
194
+ * ========================================================================== */
195
+ .rmod-body {
196
+ flex: 1;
197
+ color: var(--rmod-fg);
198
+ font-size: 0.9375rem;
199
+ line-height: 1.6;
200
+ }
201
+
202
+ /* Padding variants */
203
+ .rmod-panel[data-padding="none"] .rmod-body { padding: 0; }
204
+ .rmod-panel[data-padding="sm"] .rmod-body { padding: 0.75rem; }
205
+ .rmod-panel[data-padding="md"] .rmod-body { padding: 1.25rem; }
206
+ .rmod-panel[data-padding="lg"] .rmod-body { padding: 2rem; }
207
+
208
+ /* Scrollable body */
209
+ .rmod-panel[data-scrollable="true"] .rmod-body { overflow-y: auto; }
210
+
211
+ /* ============================================================================
212
+ * Footer
213
+ * ========================================================================== */
214
+ .rmod-footer {
215
+ display: flex;
216
+ align-items: center;
217
+ justify-content: flex-end;
218
+ gap: 0.625rem;
219
+ padding: 0.875rem 1.25rem;
220
+ background: var(--rmod-bg-footer);
221
+ border-top: 1px solid var(--rmod-border);
222
+ flex-shrink: 0;
223
+ }
224
+
225
+ /* ============================================================================
226
+ * Dark mode
227
+ * ========================================================================== */
228
+ [data-theme="dark"] .rmod-overlay {
229
+ --rmod-fg: #fafafa;
230
+ --rmod-fg-muted: #a1a1aa;
231
+ --rmod-bg: #18181b;
232
+ --rmod-bg-header: #1f1f22;
233
+ --rmod-bg-footer: #1f1f22;
234
+ --rmod-border: #3f3f46;
235
+ --rmod-overlay-bg: rgba(0, 0, 0, 0.65);
236
+ --rmod-shadow: 0 24px 64px rgba(0,0,0,0.5), 0 4px 16px rgba(0,0,0,0.3);
237
+ --rmod-close-bg-hover: #3f3f46;
238
+ --rmod-close-fg: #a1a1aa;
239
+ --rmod-close-fg-hover: #fafafa;
240
+ }
241
+
242
+ /* ============================================================================
243
+ * Reduced motion
244
+ * ========================================================================== */
245
+ @media (prefers-reduced-motion: reduce) {
246
+ .rmod-overlay, .rmod-panel { transition-duration: 0ms !important; }
247
+ }
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "@mshafiqyajid/react-modal",
3
+ "version": "0.0.0",
4
+ "description": "Headless modal hook and styled component for React. Accessible, focus-trapped, scroll-locked, animated, SSR-safe, fully typed.",
5
+ "keywords": [
6
+ "react",
7
+ "modal",
8
+ "dialog",
9
+ "drawer",
10
+ "accessible",
11
+ "headless",
12
+ "hook",
13
+ "typescript"
14
+ ],
15
+ "license": "MIT",
16
+ "author": "Shafiq Yajid",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/mshafiqyajid/packages.git",
20
+ "directory": "packages/react-modal"
21
+ },
22
+ "bugs": {
23
+ "url": "https://github.com/mshafiqyajid/packages/issues"
24
+ },
25
+ "homepage": "https://docs.shafiqyajid.com/react/modal/",
26
+ "type": "module",
27
+ "main": "./dist/index.cjs",
28
+ "module": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "import": "./dist/index.js",
34
+ "require": "./dist/index.cjs"
35
+ },
36
+ "./styled": {
37
+ "types": "./dist/styled.d.ts",
38
+ "import": "./dist/styled.js",
39
+ "require": "./dist/styled.cjs"
40
+ },
41
+ "./styles.css": "./dist/styles.css",
42
+ "./package.json": "./package.json"
43
+ },
44
+ "files": [
45
+ "dist",
46
+ "README.md",
47
+ "LICENSE"
48
+ ],
49
+ "sideEffects": [
50
+ "**/*.css"
51
+ ],
52
+ "scripts": {
53
+ "build": "tsup",
54
+ "dev": "tsup --watch",
55
+ "test": "vitest run",
56
+ "test:watch": "vitest",
57
+ "typecheck": "tsc --noEmit",
58
+ "prepublishOnly": "npm run build"
59
+ },
60
+ "peerDependencies": {
61
+ "react": ">=17.0.0"
62
+ },
63
+ "devDependencies": {
64
+ "@testing-library/jest-dom": "^6.4.0",
65
+ "@testing-library/react": "^16.0.0",
66
+ "@testing-library/user-event": "^14.5.0",
67
+ "@types/node": "^22.0.0",
68
+ "@types/react": "^18.3.0",
69
+ "@types/react-dom": "^18.3.0",
70
+ "@vitejs/plugin-react": "^4.3.0",
71
+ "jsdom": "^25.0.0",
72
+ "react": "^18.3.0",
73
+ "react-dom": "^18.3.0",
74
+ "tsup": "^8.3.0",
75
+ "typescript": "^5.6.0",
76
+ "vitest": "^2.1.0"
77
+ },
78
+ "publishConfig": {
79
+ "access": "public"
80
+ },
81
+ "engines": {
82
+ "node": ">=18"
83
+ }
84
+ }