reqwise-core 1.0.0 → 1.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/src/index.ts DELETED
@@ -1,24 +0,0 @@
1
- export * from './types'
2
- import storageDefault from './storage'
3
- import filterDefault from './filter'
4
- import i18nDefault from './i18n'
5
- import ReqwiseClientDefault from './client'
6
-
7
- export { storageDefault as storage }
8
- export { filterDefault as filter }
9
- export { i18nDefault as i18n }
10
- export { ReqwiseClientDefault as ReqwiseClient }
11
-
12
- const _default = {
13
- storage: storageDefault,
14
- filter: filterDefault,
15
- i18n: i18nDefault,
16
- ReqwiseClient: ReqwiseClientDefault,
17
- }
18
-
19
- export default _default
20
-
21
- import panel from './panel'
22
- import renderer from './renderer'
23
-
24
- export { panel, renderer }
package/src/panel.ts DELETED
@@ -1,446 +0,0 @@
1
- import styles from './styles'
2
- import i18n from './i18n'
3
- import { BANNER_DATA_URI, LOGO_DATA_URI } from './images'
4
-
5
- type Placement = 'right' | 'left' | 'top' | 'bottom'
6
-
7
- export interface PanelConfig {
8
- defaultOpen?: boolean
9
- placement?: Placement
10
- hotkey?: string
11
- theme?: 'dark' | 'light' | 'auto'
12
- }
13
-
14
- type RendererFn = (container: HTMLElement) => void
15
-
16
- const STYLE_ID = 'reqwise-styles'
17
- const PANEL_ID = 'reqwise-panel'
18
- const TOGGLE_ID = 'reqwise-toggle'
19
-
20
- function isBrowser() {
21
- return typeof document !== 'undefined' && typeof window !== 'undefined'
22
- }
23
-
24
- function parseHotkey(h?: string) {
25
- if (!h) return null
26
- const parts = h.toLowerCase().split('+').map(p => p.trim())
27
- return parts
28
- }
29
-
30
- function matchHotkey(parts: string[] | null, ev: KeyboardEvent) {
31
- if (!parts) return false
32
- const key = parts.find(p => !['ctrl', 'control', 'shift', 'alt', 'meta'].includes(p))
33
- const needCtrl = parts.includes('ctrl') || parts.includes('control')
34
- const needShift = parts.includes('shift')
35
- const needAlt = parts.includes('alt')
36
- const needMeta = parts.includes('meta')
37
- if (needCtrl !== ev.ctrlKey) return false
38
- if (needShift !== ev.shiftKey) return false
39
- if (needAlt !== ev.altKey) return false
40
- if (needMeta !== ev.metaKey) return false
41
- if (key) return ev.key.toLowerCase() === key
42
- return false
43
- }
44
-
45
- export const panel = (() => {
46
- let mounted = false
47
- let open = false
48
- let cfg: PanelConfig = {}
49
- let renderer: RendererFn | null = null
50
- let hotkeyParts: string[] | null = null
51
- let _clickOutsideHandler: ((ev: Event)=>void) | null = null
52
- let _storageUnsub: (() => void) | null = null
53
- let _scale = 1
54
- let _sizeSteps = 0
55
- const SIZE_STEP_PX = 5
56
-
57
- function injectStyles() {
58
- try {
59
- if (!isBrowser()) return
60
- if (document.getElementById(STYLE_ID)) return
61
- const s = document.createElement('style')
62
- s.id = STYLE_ID
63
- s.textContent = styles
64
- document.head.appendChild(s)
65
- } catch (e) {
66
- console.error('[reqwise] injectStyles error', e)
67
- }
68
- }
69
-
70
- function removeStyles() {
71
- try {
72
- if (!isBrowser()) return
73
- const s = document.getElementById(STYLE_ID)
74
- if (s && s.parentNode) s.parentNode.removeChild(s)
75
- } catch (e) {
76
- console.error('[reqwise] removeStyles error', e)
77
- }
78
- }
79
-
80
- function createPanelElement(): HTMLElement | null {
81
- if (!isBrowser()) return null
82
- if (document.getElementById(PANEL_ID)) return document.getElementById(PANEL_ID) as HTMLElement
83
- const aside = document.createElement('aside')
84
- aside.id = PANEL_ID
85
- aside.className = `placement-${cfg.placement || 'right'}`
86
- aside.setAttribute('role', 'region')
87
- aside.setAttribute('aria-hidden', String(!cfg.defaultOpen))
88
-
89
- const header = document.createElement('div')
90
- header.className = 'rq-header'
91
-
92
- const left = document.createElement('div')
93
- left.className = 'rq-header-left'
94
- // Use package-embedded banner image (data URI)
95
- const banner = document.createElement('img')
96
- banner.className = 'rq-banner'
97
- banner.alt = 'Reqwise'
98
- banner.src = BANNER_DATA_URI
99
- banner.style.width = '140px'
100
- banner.style.height = '42px'
101
- banner.style.objectFit = 'cover'
102
- left.appendChild(banner)
103
- header.appendChild(left)
104
-
105
- const right = document.createElement('div')
106
- right.className = 'rq-header-right'
107
-
108
- // Zoom controls (zoom out, zoom in) - placed to the left of language button
109
- const zoomControls = document.createElement('div')
110
- zoomControls.className = 'rq-zoom-controls'
111
- const zoomOutBtn = document.createElement('button')
112
- zoomOutBtn.className = 'rq-zoom-btn rq-zoom-out'
113
- zoomOutBtn.setAttribute('aria-label', 'Zoom out')
114
- zoomOutBtn.innerHTML = '<span>-</span>'
115
- const zoomInBtn = document.createElement('button')
116
- zoomInBtn.className = 'rq-zoom-btn rq-zoom-in'
117
- zoomInBtn.setAttribute('aria-label', 'Zoom in')
118
- zoomInBtn.innerHTML = '<span>+</span>'
119
- zoomControls.appendChild(zoomOutBtn)
120
- zoomControls.appendChild(zoomInBtn)
121
-
122
- const langBtn = document.createElement('button')
123
- langBtn.className = 'rq-lang-btn'
124
- langBtn.id = 'rq-lang-btn'
125
- langBtn.setAttribute('aria-label', 'Select language')
126
- langBtn.innerHTML = '<span class="rq-world">🌐</span>'
127
- // append zoom controls then language button
128
- right.appendChild(zoomControls)
129
- right.appendChild(langBtn)
130
-
131
- const dropdown = document.createElement('div')
132
- dropdown.className = 'rq-lang-dropdown'
133
- dropdown.style.display = 'none'
134
-
135
- try {
136
- const langs = i18n.availableLanguages()
137
- const current = i18n.getLanguage()
138
- langs.forEach((l) => {
139
- const item = document.createElement('button')
140
- item.className = 'rq-lang-item'
141
- ;(item as any).dataset.lang = l
142
- // show human friendly language name
143
- item.textContent = i18n.languageDisplayName(l as any)
144
- if (current === l) item.classList.add('selected')
145
- item.addEventListener('click', (ev) => {
146
- try {
147
- i18n.setLanguage(l as any)
148
- } catch (e) {}
149
- const items = dropdown.querySelectorAll('.rq-lang-item')
150
- items.forEach(it => it.classList.remove('selected'))
151
- item.classList.add('selected')
152
- dropdown.style.display = 'none'
153
- try {
154
- const body = aside.querySelector('.rq-body') as HTMLElement | null
155
- if (renderer && body) renderer(body)
156
- } catch (e) {}
157
- })
158
- dropdown.appendChild(item)
159
- })
160
- } catch (e) {}
161
-
162
- right.appendChild(dropdown)
163
-
164
- langBtn.addEventListener('click', (ev) => {
165
- try {
166
- const showing = dropdown.style.display !== 'none'
167
- dropdown.style.display = showing ? 'none' : 'block'
168
- // install/remove outside click handler
169
- if (!showing) {
170
- _clickOutsideHandler = (event: Event) => {
171
- const path = (event as any).composedPath ? (event as any).composedPath() : null
172
- if (path && path.indexOf(dropdown) >= 0) return
173
- if (path && path.indexOf(langBtn) >= 0) return
174
- dropdown.style.display = 'none'
175
- if (_clickOutsideHandler) {
176
- document.removeEventListener('click', _clickOutsideHandler)
177
- _clickOutsideHandler = null
178
- }
179
- }
180
- document.addEventListener('click', _clickOutsideHandler)
181
- } else {
182
- if (_clickOutsideHandler) {
183
- document.removeEventListener('click', _clickOutsideHandler)
184
- _clickOutsideHandler = null
185
- }
186
- }
187
- } catch (e) {}
188
- })
189
-
190
- header.appendChild(right)
191
- aside.appendChild(header)
192
-
193
- const body = document.createElement('div')
194
- body.className = 'rq-body'
195
- // Create structure placeholders for tabs and content
196
- // Renderer will populate these with actual tabs and content
197
- body.innerHTML = '<div class="rq-tabs"></div><div class="rq-main"></div>'
198
-
199
- // Wrap header+body so we can apply global scale transform without affecting panel translate
200
- const wrapper = document.createElement('div')
201
- wrapper.className = 'rq-scale-wrapper'
202
- wrapper.appendChild(header)
203
- wrapper.appendChild(body)
204
- aside.appendChild(wrapper)
205
-
206
- // add invisible corner handles to show resize cursor when hovered
207
- try {
208
- const cornerNames = ['top-left', 'top-right', 'bottom-left', 'bottom-right']
209
- cornerNames.forEach((name) => {
210
- const h = document.createElement('div')
211
- h.className = `rq-corner-handle rq-corner-${name}`
212
- aside.appendChild(h)
213
- })
214
- } catch (e) {}
215
-
216
- document.body.appendChild(aside)
217
- return aside
218
- }
219
-
220
- function createToggle() {
221
- if (!isBrowser()) return null
222
- if (document.getElementById(TOGGLE_ID)) return document.getElementById(TOGGLE_ID) as HTMLElement
223
- const btn = document.createElement('button')
224
- btn.id = TOGGLE_ID
225
- btn.className = 'rq-toggle'
226
- btn.setAttribute('aria-label', 'Toggle Reqwise DevTools')
227
-
228
- // Create logo/icon container using package-embedded image (data URI)
229
- const logo = document.createElement('img')
230
- logo.alt = 'Reqwise'
231
- logo.src = LOGO_DATA_URI
232
- logo.style.width = '32px'
233
- logo.style.height = '32px'
234
- logo.style.objectFit = 'contain'
235
-
236
- // Add text label
237
- const label = document.createElement('span')
238
- label.style.fontSize = '13px'
239
- label.style.fontWeight = '600'
240
- // initial count placeholder; will be updated by storage.subscribe
241
- label.textContent = 'Reqwise (0)'
242
- label.style.fontSize = '13px'
243
- label.style.fontWeight = '600'
244
- label.style.marginLeft = '8px'
245
-
246
- btn.appendChild(logo)
247
- btn.appendChild(label)
248
- btn.addEventListener('click', () => toggle())
249
- // Append toggle inside the panel so it stays glued to its corner and moves with the panel
250
- const p = document.getElementById(PANEL_ID)
251
- if (p) {
252
- p.appendChild(btn)
253
- } else {
254
- // fallback to body if panel not yet present
255
- document.body.appendChild(btn)
256
- }
257
-
258
- // size-step helper: adjust many px-based properties across all elements inside aside
259
- function applySizeSteps() {
260
- try {
261
- const pp = document.getElementById(PANEL_ID)
262
- if (!pp) return
263
- const all = pp.querySelectorAll<HTMLElement>('*')
264
- const cssProps = [
265
- 'font-size','padding-top','padding-right','padding-bottom','padding-left',
266
- 'margin-top','margin-right','margin-bottom','margin-left',
267
- 'border-top-left-radius','border-top-right-radius','border-bottom-left-radius','border-bottom-right-radius',
268
- 'gap'
269
- ]
270
- all.forEach((el) => {
271
- const cs = window.getComputedStyle(el)
272
- cssProps.forEach((prop) => {
273
- try {
274
- const propKey = `rqOrig_${prop.replace(/-/g, '_')}`
275
- const cur = cs.getPropertyValue(prop)
276
- if (!cur || cur === 'auto' || cur === 'normal') return
277
- // only adjust px values
278
- if (!cur.endsWith('px')) return
279
- if (!(propKey in (el.dataset as any))) {
280
- ;(el.dataset as any)[propKey] = cur
281
- }
282
- const orig = parseFloat((el.dataset as any)[propKey])
283
- if (isNaN(orig)) return
284
- const next = orig + _sizeSteps * SIZE_STEP_PX
285
- // clamp per property category
286
- let clamped = next
287
- if (prop === 'font-size') {
288
- clamped = Math.max(8, Math.min(next, 72))
289
- } else if (prop.startsWith('padding') || prop.startsWith('margin') || prop === 'gap') {
290
- clamped = Math.max(0, next)
291
- } else if (prop.includes('border') && prop.endsWith('radius')) {
292
- clamped = Math.max(0, next)
293
- }
294
- el.style.setProperty(prop, `${clamped}px`)
295
- } catch (e) {}
296
- })
297
- })
298
- } catch (e) {}
299
- }
300
-
301
- // wire zoom buttons (size-step) if present
302
- try {
303
- const p = document.getElementById(PANEL_ID)
304
- const zoomOut = p ? p.querySelector('.rq-zoom-out') as HTMLElement | null : null
305
- const zoomIn = p ? p.querySelector('.rq-zoom-in') as HTMLElement | null : null
306
- if (zoomOut) zoomOut.addEventListener('click', () => { _sizeSteps = Math.max(_sizeSteps - 1, -10); applySizeSteps() })
307
- if (zoomIn) zoomIn.addEventListener('click', () => { _sizeSteps = Math.min(_sizeSteps + 1, 10); applySizeSteps() })
308
- } catch (e) {}
309
-
310
- // subscribe to storage updates to keep the count live (lazy dynamic import)
311
- try {
312
- import('./storage.js').then((storageModule:any) => {
313
- try {
314
- if (storageModule && typeof storageModule.subscribe === 'function') {
315
- _storageUnsub = storageModule.subscribe((items: any[]) => {
316
- try { label.textContent = `Reqwise (${(items || []).length})` } catch (e) {}
317
- })
318
- }
319
- // set initial count if getEntries exists
320
- if (storageModule && typeof storageModule.getEntries === 'function') {
321
- try { const initial = storageModule.getEntries(); label.textContent = `Reqwise (${(initial || []).length})` } catch (e) {}
322
- }
323
- } catch (e) {}
324
- }).catch(()=>{})
325
- } catch (e) {}
326
-
327
- return btn
328
- }
329
-
330
- function removeToggle() {
331
- if (!isBrowser()) return
332
- const b = document.getElementById(TOGGLE_ID)
333
- if (b && b.parentNode) b.parentNode.removeChild(b)
334
- }
335
-
336
- function applyTheme() {
337
- if (!isBrowser()) return
338
- if (cfg.theme === 'light') document.documentElement.setAttribute('data-rq-theme', 'light')
339
- else if (cfg.theme === 'dark') document.documentElement.setAttribute('data-rq-theme', 'dark')
340
- else document.documentElement.removeAttribute('data-rq-theme')
341
- }
342
-
343
- function mount(config?: PanelConfig) {
344
- try {
345
- if (!isBrowser()) return
346
- if (mounted) return
347
- cfg = { defaultOpen: false, placement: 'right', hotkey: 'ctrl+shift+e', theme: 'auto', ...(config || {}) }
348
- hotkeyParts = parseHotkey(cfg.hotkey)
349
- injectStyles()
350
- applyTheme()
351
- createPanelElement()
352
- createToggle()
353
- // Ensure renderer runs at least once to populate structure and register subscriptions
354
- try {
355
- const p = document.getElementById(PANEL_ID)
356
- if (renderer && p) {
357
- const body = p.querySelector('.rq-body') as HTMLElement | null
358
- if (body) {
359
- try { renderer(body) } catch (e) { console.error('[reqwise] renderer error', e) }
360
- }
361
- }
362
- } catch (e) {}
363
- open = !!cfg.defaultOpen
364
- setOpenState(open)
365
- window.addEventListener('keydown', onKeydown)
366
- mounted = true
367
- } catch (e) {
368
- console.error('[reqwise] mount error', e)
369
- }
370
- }
371
-
372
- function onKeydown(ev: KeyboardEvent) {
373
- try {
374
- if (matchHotkey(hotkeyParts, ev)) {
375
- ev.preventDefault()
376
- toggle()
377
- }
378
- } catch (e) {
379
- console.error('[reqwise] hotkey handler', e)
380
- }
381
- }
382
-
383
- function setOpenState(next: boolean) {
384
- try {
385
- const p = document.getElementById(PANEL_ID)
386
- const t = document.getElementById(TOGGLE_ID)
387
- open = !!next
388
- if (p) {
389
- p.classList.toggle('rq-closed', !open)
390
- p.setAttribute('aria-hidden', String(!open))
391
- }
392
- // Toggle button'da hep logo + label gözüksün (text değişmesin)
393
- // call renderer with rq-body container if present
394
- if (open && renderer && p) {
395
- const body = p.querySelector('.rq-body') as HTMLElement | null
396
- if (body) {
397
- try { renderer(body) } catch (e) { console.error('[reqwise] renderer error', e) }
398
- }
399
- }
400
- } catch (e) {
401
- console.error('[reqwise] setOpenState error', e)
402
- }
403
- }
404
-
405
- function openPanel() { setOpenState(true) }
406
- function closePanel() { setOpenState(false) }
407
- function toggle() { setOpenState(!open) }
408
-
409
- function unmount() {
410
- try {
411
- if (!isBrowser()) return
412
- if (!mounted) return
413
- window.removeEventListener('keydown', onKeydown)
414
- const p = document.getElementById(PANEL_ID)
415
- if (p && p.parentNode) p.parentNode.removeChild(p)
416
- removeToggle()
417
- removeStyles()
418
- if (_storageUnsub) { try { _storageUnsub(); _storageUnsub = null } catch (e) {} }
419
- mounted = false
420
- open = false
421
- renderer = null
422
- } catch (e) {
423
- console.error('[reqwise] unmount error', e)
424
- }
425
- }
426
-
427
- function setRenderer(r: RendererFn) {
428
- renderer = r
429
- }
430
-
431
- function isMounted() { return mounted }
432
- function isOpen() { return open }
433
-
434
- return {
435
- mount,
436
- unmount,
437
- open: openPanel,
438
- close: closePanel,
439
- toggle,
440
- setRenderer,
441
- isMounted,
442
- isOpen
443
- }
444
- })()
445
-
446
- export default panel