juxscript 1.1.4 → 1.1.6
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/index.d.ts +10 -10
- package/index.d.ts.map +1 -0
- package/lib/components/alert.d.ts +32 -0
- package/lib/components/alert.d.ts.map +1 -0
- package/lib/components/alert.js +153 -0
- package/lib/components/alert.ts +200 -0
- package/lib/components/app.d.ts +89 -0
- package/lib/components/app.d.ts.map +1 -0
- package/lib/components/app.js +175 -0
- package/lib/components/app.ts +247 -0
- package/lib/components/badge.d.ts +27 -0
- package/lib/components/badge.d.ts.map +1 -0
- package/lib/components/badge.js +70 -0
- package/lib/components/badge.ts +101 -0
- package/lib/components/base/BaseComponent.d.ts +142 -0
- package/lib/components/base/BaseComponent.d.ts.map +1 -0
- package/lib/components/base/BaseComponent.js +363 -0
- package/lib/components/base/BaseComponent.ts +421 -0
- package/lib/components/base/FormInput.d.ts +73 -0
- package/lib/components/base/FormInput.d.ts.map +1 -0
- package/lib/components/base/FormInput.js +163 -0
- package/lib/components/base/FormInput.ts +227 -0
- package/lib/components/button.d.ts +48 -0
- package/lib/components/button.d.ts.map +1 -0
- package/lib/components/button.js +121 -0
- package/lib/components/button.ts +178 -0
- package/lib/components/card.d.ts +34 -0
- package/lib/components/card.d.ts.map +1 -0
- package/lib/components/card.js +127 -0
- package/lib/components/card.ts +173 -0
- package/lib/components/chart.d.ts +45 -0
- package/lib/components/chart.d.ts.map +1 -0
- package/lib/components/chart.js +186 -0
- package/lib/components/chart.ts +231 -0
- package/lib/components/checkbox.d.ts +31 -0
- package/lib/components/checkbox.d.ts.map +1 -0
- package/lib/components/checkbox.js +185 -0
- package/lib/components/checkbox.ts +242 -0
- package/lib/components/code.d.ts +24 -0
- package/lib/components/code.d.ts.map +1 -0
- package/lib/components/code.js +88 -0
- package/lib/components/code.ts +123 -0
- package/lib/components/container.d.ts +42 -0
- package/lib/components/container.d.ts.map +1 -0
- package/lib/components/container.js +93 -0
- package/lib/components/container.ts +140 -0
- package/lib/components/data.d.ts +36 -0
- package/lib/components/data.d.ts.map +1 -0
- package/lib/components/data.js +110 -0
- package/lib/components/data.ts +135 -0
- package/lib/components/datepicker.d.ts +38 -0
- package/lib/components/datepicker.d.ts.map +1 -0
- package/lib/components/datepicker.js +177 -0
- package/lib/components/datepicker.ts +234 -0
- package/lib/components/dialog.d.ts +38 -0
- package/lib/components/dialog.d.ts.map +1 -0
- package/lib/components/dialog.js +126 -0
- package/lib/components/dialog.ts +172 -0
- package/lib/components/divider.d.ts +30 -0
- package/lib/components/divider.d.ts.map +1 -0
- package/lib/components/divider.js +69 -0
- package/lib/components/divider.ts +100 -0
- package/lib/components/dropdown.d.ts +39 -0
- package/lib/components/dropdown.d.ts.map +1 -0
- package/lib/components/dropdown.js +133 -0
- package/lib/components/dropdown.ts +186 -0
- package/lib/components/element.d.ts +50 -0
- package/lib/components/element.d.ts.map +1 -0
- package/lib/components/element.js +206 -0
- package/lib/components/element.ts +267 -0
- package/lib/components/fileupload.d.ts +40 -0
- package/lib/components/fileupload.d.ts.map +1 -0
- package/lib/components/fileupload.js +241 -0
- package/lib/components/fileupload.ts +309 -0
- package/lib/components/grid.d.ts +87 -0
- package/lib/components/grid.d.ts.map +1 -0
- package/lib/components/grid.js +205 -0
- package/lib/components/grid.ts +291 -0
- package/lib/components/guard.d.ts +41 -0
- package/lib/components/guard.d.ts.map +1 -0
- package/lib/components/guard.js +56 -0
- package/lib/components/guard.ts +92 -0
- package/lib/components/heading.d.ts +24 -0
- package/lib/components/heading.d.ts.map +1 -0
- package/lib/components/heading.js +67 -0
- package/lib/components/heading.ts +96 -0
- package/lib/components/helpers.d.ts +9 -0
- package/lib/components/helpers.d.ts.map +1 -0
- package/lib/components/helpers.js +30 -0
- package/lib/components/helpers.ts +41 -0
- package/lib/components/hero.d.ts +45 -0
- package/lib/components/hero.d.ts.map +1 -0
- package/lib/components/hero.js +165 -0
- package/lib/components/hero.ts +224 -0
- package/lib/components/icon.d.ts +35 -0
- package/lib/components/icon.d.ts.map +1 -0
- package/lib/components/icon.js +132 -0
- package/lib/components/icon.ts +178 -0
- package/lib/components/icons.d.ts +25 -0
- package/lib/components/icons.d.ts.map +1 -0
- package/lib/components/icons.js +440 -0
- package/lib/components/icons.ts +464 -0
- package/lib/components/include.d.ts +120 -0
- package/lib/components/include.d.ts.map +1 -0
- package/lib/components/include.js +350 -0
- package/lib/components/include.ts +410 -0
- package/lib/components/input.d.ts +83 -0
- package/lib/components/input.d.ts.map +1 -0
- package/lib/components/input.js +348 -0
- package/lib/components/input.ts +457 -0
- package/lib/components/list.d.ts +82 -0
- package/lib/components/list.d.ts.map +1 -0
- package/lib/components/list.js +311 -0
- package/lib/components/list.ts +419 -0
- package/lib/components/loading.d.ts +24 -0
- package/lib/components/loading.d.ts.map +1 -0
- package/lib/components/loading.js +73 -0
- package/lib/components/loading.ts +100 -0
- package/lib/components/menu.d.ts +37 -0
- package/lib/components/menu.d.ts.map +1 -0
- package/lib/components/menu.js +202 -0
- package/lib/components/menu.ts +275 -0
- package/lib/components/modal.d.ts +51 -0
- package/lib/components/modal.d.ts.map +1 -0
- package/lib/components/modal.js +227 -0
- package/lib/components/modal.ts +284 -0
- package/lib/components/nav.d.ts +45 -0
- package/lib/components/nav.d.ts.map +1 -0
- package/lib/components/nav.js +190 -0
- package/lib/components/nav.ts +257 -0
- package/lib/components/paragraph.d.ts +21 -0
- package/lib/components/paragraph.d.ts.map +1 -0
- package/lib/components/paragraph.js +70 -0
- package/lib/components/paragraph.ts +97 -0
- package/lib/components/progress.d.ts +39 -0
- package/lib/components/progress.d.ts.map +1 -0
- package/lib/components/progress.js +113 -0
- package/lib/components/progress.ts +159 -0
- package/lib/components/radio.d.ts +41 -0
- package/lib/components/radio.d.ts.map +1 -0
- package/lib/components/radio.js +203 -0
- package/lib/components/radio.ts +278 -0
- package/lib/components/req.d.ts +155 -0
- package/lib/components/req.d.ts.map +1 -0
- package/lib/components/req.js +253 -0
- package/lib/components/req.ts +303 -0
- package/lib/components/script.d.ts +14 -0
- package/lib/components/script.d.ts.map +1 -0
- package/lib/components/script.js +33 -0
- package/lib/components/script.ts +41 -0
- package/lib/components/select.d.ts +40 -0
- package/lib/components/select.d.ts.map +1 -0
- package/lib/components/select.js +183 -0
- package/lib/components/select.ts +252 -0
- package/lib/components/sidebar.d.ts +48 -0
- package/lib/components/sidebar.d.ts.map +1 -0
- package/lib/components/sidebar.js +207 -0
- package/lib/components/sidebar.ts +275 -0
- package/lib/components/style.d.ts +14 -0
- package/lib/components/style.d.ts.map +1 -0
- package/lib/components/style.js +33 -0
- package/lib/components/style.ts +41 -0
- package/lib/components/switch.d.ts +32 -0
- package/lib/components/switch.d.ts.map +1 -0
- package/lib/components/switch.js +186 -0
- package/lib/components/switch.ts +246 -0
- package/lib/components/table.d.ts +137 -0
- package/lib/components/table.d.ts.map +1 -0
- package/lib/components/table.js +1045 -0
- package/lib/components/table.ts +1249 -0
- package/lib/components/tabs.d.ts +36 -0
- package/lib/components/tabs.d.ts.map +1 -0
- package/lib/components/tabs.js +198 -0
- package/lib/components/tabs.ts +250 -0
- package/lib/components/theme-toggle.d.ts +44 -0
- package/lib/components/theme-toggle.d.ts.map +1 -0
- package/lib/components/theme-toggle.js +215 -0
- package/lib/components/theme-toggle.ts +293 -0
- package/lib/components/tooltip.d.ts +30 -0
- package/lib/components/tooltip.d.ts.map +1 -0
- package/lib/components/tooltip.js +109 -0
- package/lib/components/tooltip.ts +144 -0
- package/lib/components/view.d.ts +48 -0
- package/lib/components/view.d.ts.map +1 -0
- package/lib/components/view.js +149 -0
- package/lib/components/view.ts +190 -0
- package/lib/components/write.d.ts +107 -0
- package/lib/components/write.d.ts.map +1 -0
- package/lib/components/write.js +222 -0
- package/lib/components/write.ts +272 -0
- package/lib/layouts/default.css +260 -0
- package/lib/layouts/figma.css +334 -0
- package/lib/reactivity/state.d.ts +36 -0
- package/lib/reactivity/state.d.ts.map +1 -0
- package/lib/reactivity/state.js +67 -0
- package/lib/reactivity/state.ts +78 -0
- package/lib/utils/fetch.d.ts +176 -0
- package/lib/utils/fetch.d.ts.map +1 -0
- package/lib/utils/fetch.js +427 -0
- package/lib/utils/fetch.ts +553 -0
- package/machinery/compiler3.js +78 -0
- package/machinery/doc-generator.js +136 -0
- package/machinery/imports.js +155 -0
- package/machinery/ts-shim.js +46 -0
- package/package.json +9 -15
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { FormInput, FormInputState } from './base/FormInput.js';
|
|
2
|
+
|
|
3
|
+
// Event definitions
|
|
4
|
+
const TRIGGER_EVENTS = [] as const;
|
|
5
|
+
const CALLBACK_EVENTS = ['change'] as const;
|
|
6
|
+
|
|
7
|
+
export interface RadioOption {
|
|
8
|
+
label: string;
|
|
9
|
+
value: string;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface RadioOptions {
|
|
14
|
+
options?: RadioOption[];
|
|
15
|
+
value?: string;
|
|
16
|
+
label?: string;
|
|
17
|
+
required?: boolean;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
name?: string;
|
|
20
|
+
orientation?: 'vertical' | 'horizontal'; // ✅ Add orientation
|
|
21
|
+
style?: string;
|
|
22
|
+
class?: string;
|
|
23
|
+
onValidate?: (value: string) => boolean | string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface RadioState extends FormInputState {
|
|
27
|
+
options: RadioOption[];
|
|
28
|
+
value: string;
|
|
29
|
+
orientation: 'vertical' | 'horizontal'; // ✅ Add to state
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class Radio extends FormInput<RadioState> {
|
|
33
|
+
private _radioInputs: HTMLInputElement[] = [];
|
|
34
|
+
|
|
35
|
+
constructor(id: string, options: RadioOptions = {}) {
|
|
36
|
+
super(id, {
|
|
37
|
+
options: options.options ?? [],
|
|
38
|
+
value: options.value ?? '',
|
|
39
|
+
label: options.label ?? '',
|
|
40
|
+
required: options.required ?? false,
|
|
41
|
+
disabled: options.disabled ?? false,
|
|
42
|
+
name: options.name ?? id,
|
|
43
|
+
orientation: options.orientation ?? 'vertical', // ✅ Default to vertical
|
|
44
|
+
style: options.style ?? '',
|
|
45
|
+
class: options.class ?? '',
|
|
46
|
+
errorMessage: undefined
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (options.onValidate) {
|
|
50
|
+
this._onValidate = options.onValidate;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
protected getTriggerEvents(): readonly string[] {
|
|
55
|
+
return TRIGGER_EVENTS;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
protected getCallbackEvents(): readonly string[] {
|
|
59
|
+
return CALLBACK_EVENTS;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
63
|
+
* FLUENT API
|
|
64
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
65
|
+
|
|
66
|
+
// ✅ Inherited from FormInput/BaseComponent:
|
|
67
|
+
// - label(), required(), name(), onValidate()
|
|
68
|
+
// - validate(), isValid()
|
|
69
|
+
// - style(), class()
|
|
70
|
+
// - bind(), sync(), renderTo()
|
|
71
|
+
// - disabled(), enable(), disable()
|
|
72
|
+
|
|
73
|
+
options(value: RadioOption[]): this {
|
|
74
|
+
this.state.options = value;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
value(value: string): this {
|
|
79
|
+
return this.setValue(value);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
addOption(option: RadioOption): this {
|
|
83
|
+
this.state.options = [...this.state.options, option];
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
orientation(value: 'vertical' | 'horizontal'): this {
|
|
88
|
+
this.state.orientation = value;
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
93
|
+
* FORM INPUT IMPLEMENTATION
|
|
94
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
95
|
+
|
|
96
|
+
getValue(): string {
|
|
97
|
+
return this.state.value;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
setValue(value: string): this {
|
|
101
|
+
this.state.value = value;
|
|
102
|
+
|
|
103
|
+
// Update all radio inputs
|
|
104
|
+
this._radioInputs.forEach(input => {
|
|
105
|
+
input.checked = input.value === value;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return this;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
protected _validateValue(value: string): boolean | string {
|
|
112
|
+
const { required, options } = this.state;
|
|
113
|
+
|
|
114
|
+
if (required && !value) {
|
|
115
|
+
return 'Please select an option';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Validate that value is one of the options
|
|
119
|
+
if (value && !options.some(opt => opt.value === value)) {
|
|
120
|
+
return 'Invalid option selected';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (this._onValidate) {
|
|
124
|
+
const result = this._onValidate(value);
|
|
125
|
+
if (result !== true) {
|
|
126
|
+
return result || 'Invalid value';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
protected _buildInputElement(): HTMLElement {
|
|
134
|
+
// Radio uses a container, not a single input
|
|
135
|
+
const container = document.createElement('div');
|
|
136
|
+
container.className = 'jux-radio-options';
|
|
137
|
+
return container;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* ═════════════════════════════════════════════════════════════════
|
|
141
|
+
* RENDER
|
|
142
|
+
* ═════════════════════════════════════════════════════════════════ */
|
|
143
|
+
|
|
144
|
+
render(targetId?: string): this {
|
|
145
|
+
const container = this._setupContainer(targetId);
|
|
146
|
+
|
|
147
|
+
const { options, value, name, disabled, orientation, style, class: className } = this.state; // ✅ Destructure orientation
|
|
148
|
+
|
|
149
|
+
// Build wrapper
|
|
150
|
+
const wrapper = document.createElement('div');
|
|
151
|
+
wrapper.className = 'jux-radio';
|
|
152
|
+
wrapper.id = this._id;
|
|
153
|
+
if (className) wrapper.className += ` ${className}`;
|
|
154
|
+
if (style) wrapper.setAttribute('style', style);
|
|
155
|
+
|
|
156
|
+
// Label
|
|
157
|
+
if (this.state.label) {
|
|
158
|
+
wrapper.appendChild(this._renderLabel());
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Radio options container
|
|
162
|
+
const optionsContainer = document.createElement('div');
|
|
163
|
+
optionsContainer.className = `jux-radio-options jux-radio-${orientation}`; // ✅ Add orientation class
|
|
164
|
+
this._inputElement = optionsContainer;
|
|
165
|
+
|
|
166
|
+
this._radioInputs = [];
|
|
167
|
+
|
|
168
|
+
options.forEach((option, index) => {
|
|
169
|
+
const radioWrapper = document.createElement('label');
|
|
170
|
+
radioWrapper.className = 'jux-radio-option';
|
|
171
|
+
|
|
172
|
+
const input = document.createElement('input');
|
|
173
|
+
input.type = 'radio';
|
|
174
|
+
input.className = 'jux-radio-input';
|
|
175
|
+
input.id = `${this._id}-option-${index}`;
|
|
176
|
+
input.name = name;
|
|
177
|
+
input.value = option.value;
|
|
178
|
+
input.checked = option.value === value;
|
|
179
|
+
input.disabled = disabled || option.disabled || false;
|
|
180
|
+
|
|
181
|
+
this._radioInputs.push(input);
|
|
182
|
+
|
|
183
|
+
const radioMark = document.createElement('span');
|
|
184
|
+
radioMark.className = 'jux-radio-mark';
|
|
185
|
+
|
|
186
|
+
const labelText = document.createElement('span');
|
|
187
|
+
labelText.className = 'jux-radio-label-text';
|
|
188
|
+
labelText.textContent = option.label;
|
|
189
|
+
|
|
190
|
+
radioWrapper.appendChild(input);
|
|
191
|
+
radioWrapper.appendChild(radioMark);
|
|
192
|
+
radioWrapper.appendChild(labelText);
|
|
193
|
+
|
|
194
|
+
optionsContainer.appendChild(radioWrapper);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
wrapper.appendChild(optionsContainer);
|
|
198
|
+
|
|
199
|
+
// Error element
|
|
200
|
+
wrapper.appendChild(this._renderError());
|
|
201
|
+
|
|
202
|
+
// Wire events
|
|
203
|
+
this._wireStandardEvents(wrapper);
|
|
204
|
+
|
|
205
|
+
// Wire radio-specific sync
|
|
206
|
+
const valueSync = this._syncBindings.find(b => b.property === 'value');
|
|
207
|
+
|
|
208
|
+
if (valueSync) {
|
|
209
|
+
const { stateObj, toState, toComponent } = valueSync;
|
|
210
|
+
|
|
211
|
+
const transformToState = toState || ((v: string) => v);
|
|
212
|
+
const transformToComponent = toComponent || ((v: any) => String(v));
|
|
213
|
+
|
|
214
|
+
let isUpdating = false;
|
|
215
|
+
|
|
216
|
+
// State → Component
|
|
217
|
+
stateObj.subscribe((val: any) => {
|
|
218
|
+
if (isUpdating) return;
|
|
219
|
+
const transformed = transformToComponent(val);
|
|
220
|
+
this.setValue(transformed);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Component → State
|
|
224
|
+
this._radioInputs.forEach(input => {
|
|
225
|
+
input.addEventListener('change', () => {
|
|
226
|
+
if (isUpdating) return;
|
|
227
|
+
isUpdating = true;
|
|
228
|
+
|
|
229
|
+
const selectedValue = input.value;
|
|
230
|
+
this.state.value = selectedValue;
|
|
231
|
+
this._clearError();
|
|
232
|
+
|
|
233
|
+
const transformed = transformToState(selectedValue);
|
|
234
|
+
stateObj.set(transformed);
|
|
235
|
+
|
|
236
|
+
// 🎯 Fire the change callback event
|
|
237
|
+
this._triggerCallback('change', selectedValue);
|
|
238
|
+
|
|
239
|
+
setTimeout(() => { isUpdating = false; }, 0);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
} else {
|
|
243
|
+
// Default behavior without sync
|
|
244
|
+
this._radioInputs.forEach(input => {
|
|
245
|
+
input.addEventListener('change', () => {
|
|
246
|
+
this.state.value = input.value;
|
|
247
|
+
this._clearError();
|
|
248
|
+
|
|
249
|
+
// 🎯 Fire the change callback event
|
|
250
|
+
this._triggerCallback('change', input.value);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Always add blur validation
|
|
256
|
+
this._radioInputs.forEach(input => {
|
|
257
|
+
input.addEventListener('blur', () => {
|
|
258
|
+
this.validate();
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Sync label changes
|
|
263
|
+
const labelSync = this._syncBindings.find(b => b.property === 'label');
|
|
264
|
+
if (labelSync) {
|
|
265
|
+
const transform = labelSync.toComponent || ((v: any) => String(v));
|
|
266
|
+
labelSync.stateObj.subscribe((val: any) => {
|
|
267
|
+
this.label(transform(val));
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
container.appendChild(wrapper);
|
|
272
|
+
return this;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export function radio(id: string, options: RadioOptions = {}): Radio {
|
|
277
|
+
return new Radio(id, options);
|
|
278
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request information and utilities
|
|
3
|
+
* Provides access to URL, query params, path, referrer, etc.
|
|
4
|
+
*/
|
|
5
|
+
export interface RequestInfo {
|
|
6
|
+
url: string;
|
|
7
|
+
path: string;
|
|
8
|
+
query: Record<string, string>;
|
|
9
|
+
params: Record<string, string>;
|
|
10
|
+
hash: string;
|
|
11
|
+
referrer: string;
|
|
12
|
+
method: string;
|
|
13
|
+
headers: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
export declare class Req {
|
|
16
|
+
private static _instance;
|
|
17
|
+
private _info;
|
|
18
|
+
private constructor();
|
|
19
|
+
/**
|
|
20
|
+
* Singleton instance
|
|
21
|
+
*/
|
|
22
|
+
static get instance(): Req;
|
|
23
|
+
/**
|
|
24
|
+
* Parse current request information
|
|
25
|
+
*/
|
|
26
|
+
private _parseRequest;
|
|
27
|
+
/**
|
|
28
|
+
* Get full URL
|
|
29
|
+
*/
|
|
30
|
+
get url(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Get current path (e.g., "/examples/sample/dashboards")
|
|
33
|
+
*/
|
|
34
|
+
get path(): string;
|
|
35
|
+
/**
|
|
36
|
+
* Get query string parameters
|
|
37
|
+
*/
|
|
38
|
+
get query(): Record<string, string>;
|
|
39
|
+
/**
|
|
40
|
+
* Get path parameters
|
|
41
|
+
*/
|
|
42
|
+
get params(): Record<string, string>;
|
|
43
|
+
/**
|
|
44
|
+
* Get URL hash (without #)
|
|
45
|
+
*/
|
|
46
|
+
get hash(): string;
|
|
47
|
+
/**
|
|
48
|
+
* Get referrer URL
|
|
49
|
+
*/
|
|
50
|
+
get referrer(): string;
|
|
51
|
+
/**
|
|
52
|
+
* Get request method (always GET for browser)
|
|
53
|
+
*/
|
|
54
|
+
get method(): string;
|
|
55
|
+
/**
|
|
56
|
+
* Get request headers
|
|
57
|
+
*/
|
|
58
|
+
get headers(): Record<string, string>;
|
|
59
|
+
/**
|
|
60
|
+
* Check if current path matches a pattern
|
|
61
|
+
* @param pattern - Path pattern (supports wildcards)
|
|
62
|
+
*
|
|
63
|
+
* Examples:
|
|
64
|
+
* req.matches('/examples/sample/*')
|
|
65
|
+
* req.matches('/examples/sample/dashboards')
|
|
66
|
+
* req.matches('/examples/*\/dashboards')
|
|
67
|
+
*/
|
|
68
|
+
matches(pattern: string): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Check if current path starts with prefix
|
|
71
|
+
*/
|
|
72
|
+
startsWith(prefix: string): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Check if current path ends with suffix
|
|
75
|
+
*/
|
|
76
|
+
endsWith(suffix: string): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Get query parameter value
|
|
79
|
+
*/
|
|
80
|
+
getQuery(key: string, defaultValue?: string): string | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Get path parameter value
|
|
83
|
+
*/
|
|
84
|
+
getParam(key: string, defaultValue?: string): string | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* Check if query parameter exists
|
|
87
|
+
*/
|
|
88
|
+
hasQuery(key: string): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Get all query parameters as URLSearchParams
|
|
91
|
+
*/
|
|
92
|
+
getSearchParams(): URLSearchParams;
|
|
93
|
+
/**
|
|
94
|
+
* Refresh request info (call after navigation)
|
|
95
|
+
*/
|
|
96
|
+
refresh(): void;
|
|
97
|
+
/**
|
|
98
|
+
* Set active state on nav items based on current path
|
|
99
|
+
* @param items - Nav items to update
|
|
100
|
+
* @returns Updated nav items with active state set
|
|
101
|
+
*/
|
|
102
|
+
setActiveNavItems(items: Array<{
|
|
103
|
+
href: string;
|
|
104
|
+
active?: boolean;
|
|
105
|
+
}>): Array<{
|
|
106
|
+
href: string;
|
|
107
|
+
active: boolean;
|
|
108
|
+
}>;
|
|
109
|
+
/**
|
|
110
|
+
* Check if a nav item should be active based on current path
|
|
111
|
+
* @param href - The nav item's href
|
|
112
|
+
*/
|
|
113
|
+
isActiveNavItem(href: string): boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Get breadcrumbs from current path
|
|
116
|
+
* @returns Array of breadcrumb objects with label and href
|
|
117
|
+
*/
|
|
118
|
+
getBreadcrumbs(): Array<{
|
|
119
|
+
label: string;
|
|
120
|
+
href: string;
|
|
121
|
+
}>;
|
|
122
|
+
/**
|
|
123
|
+
* Format segment into readable breadcrumb label
|
|
124
|
+
*/
|
|
125
|
+
private _formatBreadcrumbLabel;
|
|
126
|
+
/**
|
|
127
|
+
* Check if this is the home/root path
|
|
128
|
+
*/
|
|
129
|
+
get isHome(): boolean;
|
|
130
|
+
/**
|
|
131
|
+
* Get current domain
|
|
132
|
+
*/
|
|
133
|
+
get domain(): string;
|
|
134
|
+
/**
|
|
135
|
+
* Get current port
|
|
136
|
+
*/
|
|
137
|
+
get port(): string;
|
|
138
|
+
/**
|
|
139
|
+
* Get current protocol
|
|
140
|
+
*/
|
|
141
|
+
get protocol(): string;
|
|
142
|
+
/**
|
|
143
|
+
* Check if HTTPS
|
|
144
|
+
*/
|
|
145
|
+
get isSecure(): boolean;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Global request instance
|
|
149
|
+
*/
|
|
150
|
+
export declare const req: Req;
|
|
151
|
+
/**
|
|
152
|
+
* Factory function (returns singleton)
|
|
153
|
+
*/
|
|
154
|
+
export declare function request(): Req;
|
|
155
|
+
//# sourceMappingURL=req.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"req.d.ts","sourceRoot":"","sources":["req.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request information and utilities
|
|
3
|
+
* Provides access to URL, query params, path, referrer, etc.
|
|
4
|
+
*/
|
|
5
|
+
export class Req {
|
|
6
|
+
constructor() {
|
|
7
|
+
this._info = this._parseRequest();
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Singleton instance
|
|
11
|
+
*/
|
|
12
|
+
static get instance() {
|
|
13
|
+
if (!Req._instance) {
|
|
14
|
+
Req._instance = new Req();
|
|
15
|
+
}
|
|
16
|
+
return Req._instance;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Parse current request information
|
|
20
|
+
*/
|
|
21
|
+
_parseRequest() {
|
|
22
|
+
const url = new URL(window.location.href);
|
|
23
|
+
// Parse query string
|
|
24
|
+
const query = {};
|
|
25
|
+
url.searchParams.forEach((value, key) => {
|
|
26
|
+
query[key] = value;
|
|
27
|
+
});
|
|
28
|
+
// Parse path segments as params (basic routing)
|
|
29
|
+
const pathSegments = url.pathname.split('/').filter(s => s);
|
|
30
|
+
const params = {};
|
|
31
|
+
pathSegments.forEach((segment, index) => {
|
|
32
|
+
params[`${index}`] = segment;
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
url: url.href,
|
|
36
|
+
path: url.pathname,
|
|
37
|
+
query,
|
|
38
|
+
params,
|
|
39
|
+
hash: url.hash.slice(1), // Remove leading #
|
|
40
|
+
referrer: document.referrer,
|
|
41
|
+
method: 'GET', // Browser requests are always GET initially
|
|
42
|
+
headers: {
|
|
43
|
+
'user-agent': navigator.userAgent,
|
|
44
|
+
'accept-language': navigator.language
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get full URL
|
|
50
|
+
*/
|
|
51
|
+
get url() {
|
|
52
|
+
return this._info.url;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get current path (e.g., "/examples/sample/dashboards")
|
|
56
|
+
*/
|
|
57
|
+
get path() {
|
|
58
|
+
// Always get fresh path from current URL
|
|
59
|
+
return window.location.pathname;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get query string parameters
|
|
63
|
+
*/
|
|
64
|
+
get query() {
|
|
65
|
+
return { ...this._info.query };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get path parameters
|
|
69
|
+
*/
|
|
70
|
+
get params() {
|
|
71
|
+
return { ...this._info.params };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get URL hash (without #)
|
|
75
|
+
*/
|
|
76
|
+
get hash() {
|
|
77
|
+
return this._info.hash;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get referrer URL
|
|
81
|
+
*/
|
|
82
|
+
get referrer() {
|
|
83
|
+
return this._info.referrer;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get request method (always GET for browser)
|
|
87
|
+
*/
|
|
88
|
+
get method() {
|
|
89
|
+
return this._info.method;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get request headers
|
|
93
|
+
*/
|
|
94
|
+
get headers() {
|
|
95
|
+
return { ...this._info.headers };
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Check if current path matches a pattern
|
|
99
|
+
* @param pattern - Path pattern (supports wildcards)
|
|
100
|
+
*
|
|
101
|
+
* Examples:
|
|
102
|
+
* req.matches('/examples/sample/*')
|
|
103
|
+
* req.matches('/examples/sample/dashboards')
|
|
104
|
+
* req.matches('/examples/*\/dashboards')
|
|
105
|
+
*/
|
|
106
|
+
matches(pattern) {
|
|
107
|
+
const regexPattern = pattern
|
|
108
|
+
.replace(/\*/g, '.*')
|
|
109
|
+
.replace(/\//g, '\\/');
|
|
110
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
111
|
+
return regex.test(this.path);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Check if current path starts with prefix
|
|
115
|
+
*/
|
|
116
|
+
startsWith(prefix) {
|
|
117
|
+
return this.path.startsWith(prefix);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Check if current path ends with suffix
|
|
121
|
+
*/
|
|
122
|
+
endsWith(suffix) {
|
|
123
|
+
return this.path.endsWith(suffix);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get query parameter value
|
|
127
|
+
*/
|
|
128
|
+
getQuery(key, defaultValue) {
|
|
129
|
+
return this.query[key] ?? defaultValue;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get path parameter value
|
|
133
|
+
*/
|
|
134
|
+
getParam(key, defaultValue) {
|
|
135
|
+
return this.params[key] ?? defaultValue;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Check if query parameter exists
|
|
139
|
+
*/
|
|
140
|
+
hasQuery(key) {
|
|
141
|
+
return key in this.query;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Get all query parameters as URLSearchParams
|
|
145
|
+
*/
|
|
146
|
+
getSearchParams() {
|
|
147
|
+
return new URLSearchParams(this.query);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Refresh request info (call after navigation)
|
|
151
|
+
*/
|
|
152
|
+
refresh() {
|
|
153
|
+
this._info = this._parseRequest();
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Set active state on nav items based on current path
|
|
157
|
+
* @param items - Nav items to update
|
|
158
|
+
* @returns Updated nav items with active state set
|
|
159
|
+
*/
|
|
160
|
+
setActiveNavItems(items) {
|
|
161
|
+
return items.map(item => ({
|
|
162
|
+
...item,
|
|
163
|
+
active: this.isActiveNavItem(item.href)
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Check if a nav item should be active based on current path
|
|
168
|
+
* @param href - The nav item's href
|
|
169
|
+
*/
|
|
170
|
+
isActiveNavItem(href) {
|
|
171
|
+
// Exact match
|
|
172
|
+
if (href === this.path) {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
// Starts with match (for parent routes)
|
|
176
|
+
// Must be followed by a path separator or end of string
|
|
177
|
+
// e.g., "/examples/sample" matches "/examples/sample/dashboards"
|
|
178
|
+
// but "/examples/sam" does NOT match "/examples/sample/dashboards"
|
|
179
|
+
if (href !== '/' && (this.path === href || this.path.startsWith(href + '/'))) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get breadcrumbs from current path
|
|
186
|
+
* @returns Array of breadcrumb objects with label and href
|
|
187
|
+
*/
|
|
188
|
+
getBreadcrumbs() {
|
|
189
|
+
const segments = this.path.split('/').filter(s => s);
|
|
190
|
+
const breadcrumbs = [
|
|
191
|
+
{ label: 'Home', href: '/' }
|
|
192
|
+
];
|
|
193
|
+
let currentPath = '';
|
|
194
|
+
segments.forEach(segment => {
|
|
195
|
+
currentPath += `/${segment}`;
|
|
196
|
+
breadcrumbs.push({
|
|
197
|
+
label: this._formatBreadcrumbLabel(segment),
|
|
198
|
+
href: currentPath
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
return breadcrumbs;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Format segment into readable breadcrumb label
|
|
205
|
+
*/
|
|
206
|
+
_formatBreadcrumbLabel(segment) {
|
|
207
|
+
return segment
|
|
208
|
+
.split('-')
|
|
209
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
210
|
+
.join(' ');
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Check if this is the home/root path
|
|
214
|
+
*/
|
|
215
|
+
get isHome() {
|
|
216
|
+
return this.path === '/' || this.path === '';
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Get current domain
|
|
220
|
+
*/
|
|
221
|
+
get domain() {
|
|
222
|
+
return window.location.hostname;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Get current port
|
|
226
|
+
*/
|
|
227
|
+
get port() {
|
|
228
|
+
return window.location.port;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Get current protocol
|
|
232
|
+
*/
|
|
233
|
+
get protocol() {
|
|
234
|
+
return window.location.protocol.replace(':', '');
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Check if HTTPS
|
|
238
|
+
*/
|
|
239
|
+
get isSecure() {
|
|
240
|
+
return this.protocol === 'https';
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
Req._instance = null;
|
|
244
|
+
/**
|
|
245
|
+
* Global request instance
|
|
246
|
+
*/
|
|
247
|
+
export const req = Req.instance;
|
|
248
|
+
/**
|
|
249
|
+
* Factory function (returns singleton)
|
|
250
|
+
*/
|
|
251
|
+
export function request() {
|
|
252
|
+
return Req.instance;
|
|
253
|
+
}
|