@quicdata/analytics 0.0.3 → 0.0.5

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.
Files changed (71) hide show
  1. package/analytics.css +69 -0
  2. package/core/auth.d.ts +19 -0
  3. package/core/auth.d.ts.map +1 -0
  4. package/core/auth.js +34 -0
  5. package/core/fetch-data.d.ts +115 -0
  6. package/core/fetch-data.d.ts.map +1 -0
  7. package/core/fetch-data.js +210 -0
  8. package/core/index.d.ts +8 -1
  9. package/core/index.d.ts.map +1 -1
  10. package/core/index.js +4 -3
  11. package/core/types.d.ts +250 -0
  12. package/core/types.d.ts.map +1 -0
  13. package/core/types.js +1 -0
  14. package/core/viewport-observer.d.ts +26 -0
  15. package/core/viewport-observer.d.ts.map +1 -0
  16. package/core/viewport-observer.js +38 -0
  17. package/core/widget-transform-runner.d.ts +22 -0
  18. package/core/widget-transform-runner.d.ts.map +1 -0
  19. package/core/widget-transform-runner.js +102 -0
  20. package/dashboard/dashboard-container.d.ts +100 -0
  21. package/dashboard/dashboard-container.d.ts.map +1 -0
  22. package/dashboard/dashboard-container.js +315 -0
  23. package/dashboard/index.d.ts +4 -0
  24. package/dashboard/index.d.ts.map +1 -0
  25. package/dashboard/index.js +2 -0
  26. package/designer/analytics-designer.d.ts +40 -0
  27. package/designer/analytics-designer.d.ts.map +1 -0
  28. package/designer/analytics-designer.js +267 -0
  29. package/designer/index.d.ts +5 -0
  30. package/designer/index.d.ts.map +1 -0
  31. package/designer/index.js +3 -0
  32. package/filters/filter-bar.d.ts +34 -0
  33. package/filters/filter-bar.d.ts.map +1 -0
  34. package/filters/filter-bar.js +233 -0
  35. package/filters/filter-button.d.ts +22 -0
  36. package/filters/filter-button.d.ts.map +1 -0
  37. package/filters/filter-button.js +86 -0
  38. package/filters/index.d.ts +7 -0
  39. package/filters/index.d.ts.map +1 -0
  40. package/filters/index.js +6 -0
  41. package/filters/widget-toolbar.d.ts +24 -0
  42. package/filters/widget-toolbar.d.ts.map +1 -0
  43. package/filters/widget-toolbar.js +219 -0
  44. package/index.d.ts +9 -1
  45. package/index.js +6 -1
  46. package/package.json +34 -9
  47. package/widgets/analytics-report.d.ts +49 -0
  48. package/widgets/analytics-report.d.ts.map +1 -0
  49. package/widgets/analytics-report.js +306 -0
  50. package/widgets/analytics-widget.d.ts +39 -0
  51. package/widgets/analytics-widget.d.ts.map +1 -0
  52. package/widgets/analytics-widget.js +230 -0
  53. package/widgets/bar-chart.d.ts +13 -0
  54. package/widgets/bar-chart.d.ts.map +1 -0
  55. package/widgets/bar-chart.js +77 -0
  56. package/widgets/base-chart.d.ts +92 -0
  57. package/widgets/base-chart.d.ts.map +1 -0
  58. package/widgets/base-chart.js +524 -0
  59. package/widgets/index.d.ts +13 -1
  60. package/widgets/index.d.ts.map +1 -1
  61. package/widgets/index.js +14 -3
  62. package/widgets/line-chart.d.ts +13 -0
  63. package/widgets/line-chart.d.ts.map +1 -0
  64. package/widgets/line-chart.js +71 -0
  65. package/widgets/pie-chart.d.ts +13 -0
  66. package/widgets/pie-chart.d.ts.map +1 -0
  67. package/widgets/pie-chart.js +55 -0
  68. package/widgets/table.d.ts +96 -0
  69. package/widgets/table.d.ts.map +1 -0
  70. package/widgets/table.js +721 -0
  71. package/index.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter-bar.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/filters/filter-bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAE5C,OAAO,KAAK,EAAE,gBAAgB,EAAgB,MAAM,kBAAkB,CAAC;AAEvE,eAAO,MAAM,mBAAmB,4BAA4B,CAAC;AAC7D,eAAO,MAAM,kBAAkB,2BAA2B,CAAC;AAE3D;;;GAGG;AACH,qBACa,kBAAmB,SAAQ,UAAU;IAChD,OAAgB,MAAM,0BAsEpB;IAEF,sDAAsD;IAC3B,OAAO,EAAE,gBAAgB,EAAE,CAAM;IAE5D,iDAAiD;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAM;IAEnF,wCAAwC;IACX,SAAS,UAAQ;IAE9C,sLAAsL;IACtL,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,MAAM;IAId,mJAAmJ;IACnJ,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,cAAc;IA2Eb,MAAM;CAgBhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,sBAAsB,EAAE,kBAAkB,CAAC;KAC5C;CACF"}
@@ -0,0 +1,233 @@
1
+ import { __decorate } from "tslib";
2
+ import { LitElement, html, css } from 'lit';
3
+ import { customElement, property } from 'lit/decorators.js';
4
+ export const EVENT_FILTER_CHANGE = 'analytics-filter-change';
5
+ export const EVENT_FILTER_CLOSE = 'analytics-filter-close';
6
+ /**
7
+ * Filter bar: renders a row of filter controls from filter definitions.
8
+ * Emits analytics-filter-change when any value changes; analytics-filter-close when close is clicked.
9
+ */
10
+ let AnalyticsFilterBar = class AnalyticsFilterBar extends LitElement {
11
+ constructor() {
12
+ super(...arguments);
13
+ /** Filter definitions (param_name, type, options). */
14
+ this.filters = [];
15
+ /** Current filter values keyed by param_name. */
16
+ this.values = {};
17
+ /** Whether to show the close button. */
18
+ this.showClose = true;
19
+ }
20
+ static { this.styles = css `
21
+ :host {
22
+ display: block;
23
+ }
24
+ .bar {
25
+ display: flex;
26
+ flex-wrap: wrap;
27
+ align-items: center;
28
+ gap: 0.75rem 1rem;
29
+ padding: 0.75rem 1rem;
30
+ background: var(--analytics-filter-bar-bg, transparent);
31
+ border: none;
32
+ border-radius: 0.5rem;
33
+ }
34
+ .group {
35
+ display: flex;
36
+ align-items: center;
37
+ gap: 0.5rem;
38
+ }
39
+ label {
40
+ font-size: 0.8125rem;
41
+ font-weight: 500;
42
+ color: var(--analytics-filter-bar-label-color, #475569);
43
+ white-space: nowrap;
44
+ }
45
+ select,
46
+ input[type='text'],
47
+ input[type='number'],
48
+ input[type='date'] {
49
+ padding: 0.375rem 0.5rem;
50
+ font-size: 0.875rem;
51
+ border: 1px solid var(--analytics-filter-bar-input-border, #cbd5e1);
52
+ border-radius: 0.375rem;
53
+ min-width: 8rem;
54
+ background: var(--analytics-filter-bar-input-bg, #fff);
55
+ color: var(--analytics-filter-bar-input-color, inherit);
56
+ }
57
+ select:focus,
58
+ input:focus {
59
+ outline: none;
60
+ border-color: #3b82f6;
61
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
62
+ }
63
+ .actions {
64
+ margin-left: auto;
65
+ display: flex;
66
+ align-items: center;
67
+ gap: 0.5rem;
68
+ }
69
+ .btn {
70
+ padding: 0.375rem 0.75rem;
71
+ font-size: 0.8125rem;
72
+ border-radius: 0.375rem;
73
+ cursor: pointer;
74
+ border: 1px solid var(--analytics-filter-bar-border, #e2e8f0);
75
+ background: transparent;
76
+ color: var(--analytics-filter-bar-close-color, #64748b);
77
+ }
78
+ .btn:hover {
79
+ background: var(--analytics-filter-bar-close-hover-bg, #f1f5f9);
80
+ color: var(--analytics-filter-bar-close-hover-color, #334155);
81
+ }
82
+ .btn-clear {
83
+ color: #0ea5e9;
84
+ border-color: rgba(14, 165, 233, 0.4);
85
+ }
86
+ .btn-clear:hover {
87
+ background: rgba(14, 165, 233, 0.08);
88
+ color: #0284c7;
89
+ }
90
+ `; }
91
+ /** Build params to send: use default_value only when param was never set (undefined). User input or Clear sets explicit value (including ''), so we do not use default_value then. */
92
+ _effectiveParams() {
93
+ const out = {};
94
+ for (const def of this.filters) {
95
+ const current = this.values[def.param_name];
96
+ const neverSet = !(def.param_name in this.values) || current === undefined;
97
+ out[def.param_name] = neverSet ? (def.default_value ?? '') : (current ?? '');
98
+ }
99
+ return out;
100
+ }
101
+ _emitChange() {
102
+ this.dispatchEvent(new CustomEvent(EVENT_FILTER_CHANGE, {
103
+ bubbles: true,
104
+ composed: true,
105
+ detail: { params: this._effectiveParams() },
106
+ }));
107
+ }
108
+ _onInput(paramName, value) {
109
+ this.values = { ...this.values, [paramName]: value };
110
+ this._emitChange();
111
+ }
112
+ _onClear() {
113
+ const empty = {};
114
+ for (const def of this.filters) {
115
+ empty[def.param_name] = '';
116
+ }
117
+ this.values = empty;
118
+ this._emitChange();
119
+ }
120
+ _onClose() {
121
+ this.dispatchEvent(new CustomEvent(EVENT_FILTER_CLOSE, {
122
+ bubbles: true,
123
+ composed: true,
124
+ }));
125
+ }
126
+ _label(def) {
127
+ return (def.label != null && def.label !== '') ? def.label : def.param_name;
128
+ }
129
+ /** Display value: show default_value only when param was never set (rerender). After user input or Clear, show the actual value (including ''). */
130
+ _effectiveValue(def) {
131
+ const v = this.values[def.param_name];
132
+ const neverSet = !(def.param_name in this.values) || v === undefined;
133
+ if (neverSet)
134
+ return def.default_value ?? '';
135
+ return v ?? '';
136
+ }
137
+ _renderControl(def) {
138
+ const value = this._effectiveValue(def);
139
+ const options = (def.options ?? []);
140
+ const label = this._label(def);
141
+ if (def.type === 'preset' || (options.length > 0 && ['select', 'dropdown'].includes(def.type))) {
142
+ const current = (value !== '' && value != null ? String(value) : '');
143
+ return html `
144
+ <div class="group">
145
+ <label for="filter-${def.param_name}">${label}</label>
146
+ <select
147
+ id="filter-${def.param_name}"
148
+ .value=${current}
149
+ @change=${(e) => {
150
+ const v = e.target.value;
151
+ const opt = options.find((o) => String(o.value) === v);
152
+ this._onInput(def.param_name, opt != null ? opt.value : v);
153
+ }}
154
+ >
155
+ <option value="">—</option>
156
+ ${options.map((o) => html `<option value="${String(o.value)}" .selected=${String(o.value) === current}>
157
+ ${o.label ?? String(o.value)}
158
+ </option>`)}
159
+ </select>
160
+ </div>
161
+ `;
162
+ }
163
+ if (def.type === 'number') {
164
+ const num = typeof value === 'number' ? value : value !== '' && value != null ? Number(value) : (def.default_value != null ? Number(def.default_value) : '');
165
+ return html `
166
+ <div class="group">
167
+ <label for="filter-${def.param_name}">${label}</label>
168
+ <input
169
+ type="number"
170
+ id="filter-${def.param_name}"
171
+ .value=${num}
172
+ @input=${(e) => this._onInput(def.param_name, Number(e.target.value) || 0)}
173
+ />
174
+ </div>
175
+ `;
176
+ }
177
+ if (def.type === 'date') {
178
+ const str = (value != null && value !== '' ? String(value) : (def.default_value != null ? String(def.default_value) : ''));
179
+ return html `
180
+ <div class="group">
181
+ <label for="filter-${def.param_name}">${label}</label>
182
+ <input
183
+ type="date"
184
+ id="filter-${def.param_name}"
185
+ .value=${str}
186
+ @input=${(e) => this._onInput(def.param_name, e.target.value)}
187
+ />
188
+ </div>
189
+ `;
190
+ }
191
+ const str = (value != null && value !== '' ? String(value) : (def.default_value != null ? String(def.default_value) : ''));
192
+ return html `
193
+ <div class="group">
194
+ <label for="filter-${def.param_name}">${label}</label>
195
+ <input
196
+ type="text"
197
+ id="filter-${def.param_name}"
198
+ .value=${str}
199
+ @input=${(e) => this._onInput(def.param_name, e.target.value)}
200
+ />
201
+ </div>
202
+ `;
203
+ }
204
+ render() {
205
+ if (this.filters.length === 0) {
206
+ return html `<div class="bar"><span style="color:#64748b;font-size:0.875rem">No filters</span></div>`;
207
+ }
208
+ return html `
209
+ <div class="bar">
210
+ ${this.filters.map((def) => this._renderControl(def))}
211
+ <div class="actions">
212
+ <button type="button" class="btn btn-clear" @click=${this._onClear} title="Reset all filters to default">Clear</button>
213
+ ${this.showClose
214
+ ? html `<button type="button" class="btn" @click=${this._onClose} title="Close" aria-label="Close">×</button>`
215
+ : ''}
216
+ </div>
217
+ </div>
218
+ `;
219
+ }
220
+ };
221
+ __decorate([
222
+ property({ type: Array })
223
+ ], AnalyticsFilterBar.prototype, "filters", void 0);
224
+ __decorate([
225
+ property({ type: Object })
226
+ ], AnalyticsFilterBar.prototype, "values", void 0);
227
+ __decorate([
228
+ property({ type: Boolean })
229
+ ], AnalyticsFilterBar.prototype, "showClose", void 0);
230
+ AnalyticsFilterBar = __decorate([
231
+ customElement('analytics-filter-bar')
232
+ ], AnalyticsFilterBar);
233
+ export { AnalyticsFilterBar };
@@ -0,0 +1,22 @@
1
+ import { LitElement } from 'lit';
2
+ export declare const EVENT_FILTER_TOGGLE = "analytics-filter-toggle";
3
+ /**
4
+ * Filter button: toggles filter bar visibility.
5
+ * Dispatches analytics-filter-toggle when clicked; parent should show/hide the filter bar.
6
+ * Optionally shows a badge when activeCount > 0.
7
+ */
8
+ export declare class AnalyticsFilterButton extends LitElement {
9
+ static styles: import("lit").CSSResult;
10
+ /** Number of active filters (shows badge when > 0). */
11
+ activeCount: number;
12
+ /** Whether the filter bar is currently open (button appears active). */
13
+ open: boolean;
14
+ private _onClick;
15
+ render(): import("lit-html").TemplateResult<1>;
16
+ }
17
+ declare global {
18
+ interface HTMLElementTagNameMap {
19
+ 'analytics-filter-button': AnalyticsFilterButton;
20
+ }
21
+ }
22
+ //# sourceMappingURL=filter-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter-button.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/filters/filter-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAG5C,eAAO,MAAM,mBAAmB,4BAA4B,CAAC;AAE7D;;;;GAIG;AACH,qBACa,qBAAsB,SAAQ,UAAU;IACnD,OAAgB,MAAM,0BAqCpB;IAEF,uDAAuD;IAC3B,WAAW,SAAK;IAE5C,wEAAwE;IAC3C,IAAI,UAAS;IAE1C,OAAO,CAAC,QAAQ;IASP,MAAM;CAchB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,yBAAyB,EAAE,qBAAqB,CAAC;KAClD;CACF"}
@@ -0,0 +1,86 @@
1
+ import { __decorate } from "tslib";
2
+ import { LitElement, html, css } from 'lit';
3
+ import { customElement, property } from 'lit/decorators.js';
4
+ export const EVENT_FILTER_TOGGLE = 'analytics-filter-toggle';
5
+ /**
6
+ * Filter button: toggles filter bar visibility.
7
+ * Dispatches analytics-filter-toggle when clicked; parent should show/hide the filter bar.
8
+ * Optionally shows a badge when activeCount > 0.
9
+ */
10
+ let AnalyticsFilterButton = class AnalyticsFilterButton extends LitElement {
11
+ constructor() {
12
+ super(...arguments);
13
+ /** Number of active filters (shows badge when > 0). */
14
+ this.activeCount = 0;
15
+ /** Whether the filter bar is currently open (button appears active). */
16
+ this.open = false;
17
+ }
18
+ static { this.styles = css `
19
+ :host {
20
+ display: inline-block;
21
+ }
22
+ button {
23
+ display: inline-flex;
24
+ align-items: center;
25
+ gap: 0.375rem;
26
+ padding: 0.375rem 0.75rem;
27
+ font-size: 0.875rem;
28
+ color: #475569;
29
+ background: #fff;
30
+ border: 1px solid #e2e8f0;
31
+ border-radius: 0.375rem;
32
+ cursor: pointer;
33
+ }
34
+ button:hover {
35
+ background: #f8fafc;
36
+ border-color: #cbd5e1;
37
+ color: #334155;
38
+ }
39
+ button.active {
40
+ border-color: #3b82f6;
41
+ color: #3b82f6;
42
+ background: #eff6ff;
43
+ }
44
+ .badge {
45
+ min-width: 1.25rem;
46
+ height: 1.25rem;
47
+ padding: 0 0.25rem;
48
+ font-size: 0.75rem;
49
+ line-height: 1.25rem;
50
+ text-align: center;
51
+ background: #3b82f6;
52
+ color: #fff;
53
+ border-radius: 9999px;
54
+ }
55
+ `; }
56
+ _onClick() {
57
+ this.dispatchEvent(new CustomEvent(EVENT_FILTER_TOGGLE, {
58
+ bubbles: true,
59
+ composed: true,
60
+ }));
61
+ }
62
+ render() {
63
+ return html `
64
+ <button
65
+ type="button"
66
+ class="${this.open ? 'active' : ''}"
67
+ @click=${this._onClick}
68
+ aria-expanded="${this.open}"
69
+ aria-label="${this.open ? 'Hide filters' : 'Show filters'}"
70
+ >
71
+ <span aria-hidden="true">Filters</span>
72
+ ${this.activeCount > 0 ? html `<span class="badge">${this.activeCount}</span>` : ''}
73
+ </button>
74
+ `;
75
+ }
76
+ };
77
+ __decorate([
78
+ property({ type: Number })
79
+ ], AnalyticsFilterButton.prototype, "activeCount", void 0);
80
+ __decorate([
81
+ property({ type: Boolean })
82
+ ], AnalyticsFilterButton.prototype, "open", void 0);
83
+ AnalyticsFilterButton = __decorate([
84
+ customElement('analytics-filter-button')
85
+ ], AnalyticsFilterButton);
86
+ export { AnalyticsFilterButton };
@@ -0,0 +1,7 @@
1
+ export { AnalyticsFilterBar, EVENT_FILTER_CHANGE, EVENT_FILTER_CLOSE } from './filter-bar.js';
2
+ export { AnalyticsFilterButton, EVENT_FILTER_TOGGLE } from './filter-button.js';
3
+ export { AnalyticsWidgetToolbar } from './widget-toolbar.js';
4
+ import './filter-bar.js';
5
+ import './filter-button.js';
6
+ import './widget-toolbar.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/filters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,OAAO,iBAAiB,CAAC;AACzB,OAAO,oBAAoB,CAAC;AAC5B,OAAO,qBAAqB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { AnalyticsFilterBar, EVENT_FILTER_CHANGE, EVENT_FILTER_CLOSE } from './filter-bar.js';
2
+ export { AnalyticsFilterButton, EVENT_FILTER_TOGGLE } from './filter-button.js';
3
+ export { AnalyticsWidgetToolbar } from './widget-toolbar.js';
4
+ import './filter-bar.js';
5
+ import './filter-button.js';
6
+ import './widget-toolbar.js';
@@ -0,0 +1,24 @@
1
+ import { LitElement } from 'lit';
2
+ import type { FilterDefinition } from '../core/types.js';
3
+ /**
4
+ * Floating widget toolbar: glass-style bar at top-right, visible on hover.
5
+ * Contains filter icon; click opens a dialog with the filter form.
6
+ */
7
+ export declare class AnalyticsWidgetToolbar extends LitElement {
8
+ static styles: import("lit").CSSResult;
9
+ filters: FilterDefinition[];
10
+ values: Record<string, string | number | boolean>;
11
+ activeCount: number;
12
+ private _dialogOpen;
13
+ private _onFilterIconClick;
14
+ private _onDialogClose;
15
+ private _onFilterChange;
16
+ private _onFilterBarClose;
17
+ render(): import("lit-html").TemplateResult<1>;
18
+ }
19
+ declare global {
20
+ interface HTMLElementTagNameMap {
21
+ 'analytics-widget-toolbar': AnalyticsWidgetToolbar;
22
+ }
23
+ }
24
+ //# sourceMappingURL=widget-toolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget-toolbar.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/filters/widget-toolbar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAE5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGzD;;;GAGG;AACH,qBACa,sBAAuB,SAAQ,UAAU;IACpD,OAAgB,MAAM,0BAyHpB;IAEyB,OAAO,EAAE,gBAAgB,EAAE,CAAM;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAM;IACvD,WAAW,SAAK;IAEnC,OAAO,CAAC,WAAW,CAAS;IAErC,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,iBAAiB;IAIhB,MAAM;CA8ChB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,0BAA0B,EAAE,sBAAsB,CAAC;KACpD;CACF"}
@@ -0,0 +1,219 @@
1
+ import { __decorate } from "tslib";
2
+ import { LitElement, html, css } from 'lit';
3
+ import { customElement, property, state } from 'lit/decorators.js';
4
+ import { EVENT_FILTER_CHANGE, EVENT_FILTER_CLOSE } from './filter-bar.js';
5
+ /**
6
+ * Floating widget toolbar: glass-style bar at top-right, visible on hover.
7
+ * Contains filter icon; click opens a dialog with the filter form.
8
+ */
9
+ let AnalyticsWidgetToolbar = class AnalyticsWidgetToolbar extends LitElement {
10
+ constructor() {
11
+ super(...arguments);
12
+ this.filters = [];
13
+ this.values = {};
14
+ this.activeCount = 0;
15
+ this._dialogOpen = false;
16
+ }
17
+ static { this.styles = css `
18
+ :host {
19
+ position: absolute;
20
+ top: 0.5rem;
21
+ right: 0.5rem;
22
+ z-index: var(--analytics-widget-toolbar-z-index, 20);
23
+ opacity: 0;
24
+ transition: opacity 0.2s ease;
25
+ pointer-events: none;
26
+ }
27
+ :host(.visible) {
28
+ opacity: 1;
29
+ pointer-events: auto;
30
+ }
31
+ .toolbar {
32
+ display: inline-flex;
33
+ align-items: center;
34
+ gap: 0.25rem;
35
+ padding: 0.375rem 0.5rem;
36
+ background: rgba(0, 0, 0, 0.55);
37
+ backdrop-filter: blur(10px);
38
+ -webkit-backdrop-filter: blur(10px);
39
+ border-radius: 8px;
40
+ border: 1px solid rgba(255, 255, 255, 0.1);
41
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
42
+ }
43
+ .icon-btn {
44
+ display: inline-flex;
45
+ align-items: center;
46
+ justify-content: center;
47
+ width: 2rem;
48
+ height: 2rem;
49
+ padding: 0;
50
+ color: rgba(255, 255, 255, 0.9);
51
+ background: transparent;
52
+ border: none;
53
+ border-radius: 6px;
54
+ cursor: pointer;
55
+ position: relative;
56
+ }
57
+ .icon-btn:hover {
58
+ background: rgba(255, 255, 255, 0.15);
59
+ color: #fff;
60
+ }
61
+ .icon-btn svg {
62
+ width: 1.125rem;
63
+ height: 1.125rem;
64
+ }
65
+ .badge {
66
+ position: absolute;
67
+ top: -2px;
68
+ right: -2px;
69
+ min-width: 1rem;
70
+ height: 1rem;
71
+ padding: 0 0.2rem;
72
+ font-size: 0.65rem;
73
+ line-height: 1rem;
74
+ text-align: center;
75
+ background: #3b82f6;
76
+ color: #fff;
77
+ border-radius: 9999px;
78
+ }
79
+ .overlay {
80
+ position: fixed;
81
+ inset: 0;
82
+ z-index: var(--analytics-widget-toolbar-overlay-z-index, 1000);
83
+ background: var(--analytics-widget-toolbar-overlay-bg, rgba(0, 0, 0, 0.35));
84
+ backdrop-filter: var(--analytics-widget-toolbar-overlay-backdrop-filter, blur(2px));
85
+ -webkit-backdrop-filter: var(--analytics-widget-toolbar-overlay-backdrop-filter, blur(2px));
86
+ display: flex;
87
+ align-items: flex-start;
88
+ justify-content: center;
89
+ padding: 2rem;
90
+ box-sizing: border-box;
91
+ }
92
+ .dialog {
93
+ position: relative;
94
+ z-index: var(--analytics-widget-toolbar-dialog-z-index, 1);
95
+ background: #fff;
96
+ border-radius: 12px;
97
+ border: 1px solid #e2e8f0;
98
+ box-shadow: 0 24px 48px rgba(0, 0, 0, 0.12);
99
+ min-width: 320px;
100
+ max-width: 90vw;
101
+ max-height: 85vh;
102
+ overflow: auto;
103
+ }
104
+ .dialog-close {
105
+ position: absolute;
106
+ top: 0.5rem;
107
+ right: 0.5rem;
108
+ display: inline-flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ width: 2rem;
112
+ height: 2rem;
113
+ padding: 0;
114
+ color: #64748b;
115
+ background: transparent;
116
+ border: none;
117
+ border-radius: 6px;
118
+ cursor: pointer;
119
+ z-index: calc(var(--analytics-widget-toolbar-dialog-z-index, 1) + 1);
120
+ }
121
+ .dialog-close:hover {
122
+ background: #f1f5f9;
123
+ color: #334155;
124
+ }
125
+ .dialog-body {
126
+ padding: 2.5rem 2.5rem 1rem 1rem;
127
+ /* Light mode: use filter-bar defaults (light bg, dark text) */
128
+ --analytics-filter-bar-bg: transparent;
129
+ --analytics-filter-bar-border: transparent;
130
+ --analytics-filter-bar-label-color: #475569;
131
+ --analytics-filter-bar-input-bg: #fff;
132
+ --analytics-filter-bar-input-border: #cbd5e1;
133
+ --analytics-filter-bar-input-color: inherit;
134
+ --analytics-filter-bar-close-color: #64748b;
135
+ --analytics-filter-bar-close-hover-bg: #f1f5f9;
136
+ --analytics-filter-bar-close-hover-color: #334155;
137
+ }
138
+ `; }
139
+ _onFilterIconClick() {
140
+ this._dialogOpen = true;
141
+ }
142
+ _onDialogClose() {
143
+ this._dialogOpen = false;
144
+ this.dispatchEvent(new CustomEvent(EVENT_FILTER_CLOSE, { bubbles: true, composed: true }));
145
+ }
146
+ _onFilterChange(e) {
147
+ e.stopPropagation();
148
+ this.dispatchEvent(new CustomEvent(EVENT_FILTER_CHANGE, {
149
+ bubbles: true,
150
+ composed: true,
151
+ detail: e.detail,
152
+ }));
153
+ }
154
+ _onFilterBarClose() {
155
+ this._dialogOpen = false;
156
+ }
157
+ render() {
158
+ const hasFilters = this.filters.length > 0;
159
+ if (!hasFilters)
160
+ return html ``;
161
+ return html `
162
+ <div class="toolbar" role="toolbar">
163
+ <button
164
+ type="button"
165
+ class="icon-btn"
166
+ aria-label="Filters"
167
+ aria-haspopup="dialog"
168
+ aria-expanded="${this._dialogOpen}"
169
+ @click=${this._onFilterIconClick}
170
+ >
171
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
172
+ <polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon>
173
+ </svg>
174
+ ${this.activeCount > 0 ? html `<span class="badge">${this.activeCount}</span>` : ''}
175
+ </button>
176
+ </div>
177
+
178
+ ${this._dialogOpen
179
+ ? html `
180
+ <div class="overlay" role="dialog" aria-modal="true" aria-label="Filters" @click=${this._onDialogClose}>
181
+ <div class="dialog" @click=${(e) => e.stopPropagation()}>
182
+ <button type="button" class="dialog-close" aria-label="Close" @click=${this._onDialogClose}>
183
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
184
+ <line x1="18" y1="6" x2="6" y2="18"></line>
185
+ <line x1="6" y1="6" x2="18" y2="18"></line>
186
+ </svg>
187
+ </button>
188
+ <div class="dialog-body">
189
+ <analytics-filter-bar
190
+ .filters=${this.filters}
191
+ .values=${this.values}
192
+ .showClose=${false}
193
+ @analytics-filter-change=${this._onFilterChange}
194
+ @analytics-filter-close=${this._onFilterBarClose}
195
+ ></analytics-filter-bar>
196
+ </div>
197
+ </div>
198
+ </div>
199
+ `
200
+ : ''}
201
+ `;
202
+ }
203
+ };
204
+ __decorate([
205
+ property({ type: Array })
206
+ ], AnalyticsWidgetToolbar.prototype, "filters", void 0);
207
+ __decorate([
208
+ property({ type: Object })
209
+ ], AnalyticsWidgetToolbar.prototype, "values", void 0);
210
+ __decorate([
211
+ property({ type: Number })
212
+ ], AnalyticsWidgetToolbar.prototype, "activeCount", void 0);
213
+ __decorate([
214
+ state()
215
+ ], AnalyticsWidgetToolbar.prototype, "_dialogOpen", void 0);
216
+ AnalyticsWidgetToolbar = __decorate([
217
+ customElement('analytics-widget-toolbar')
218
+ ], AnalyticsWidgetToolbar);
219
+ export { AnalyticsWidgetToolbar };
package/index.d.ts CHANGED
@@ -1,2 +1,10 @@
1
- export {};
1
+ export { setAnalyticsApiKey, getAnalyticsApiKey, buildWidgetDataUrl, fetchAnalyticsData, fetchWidgetData, } from './core/index.js';
2
+ export type { AnalyticsDataResponse, AnalyticsDataMeta, AnalyticsRequestParams, WidgetDataResponse, WidgetDataApiResponse, WidgetDataOptions, DatetimeGranularity, DimensionRef, MeasureRef, FilterDefinition, FilterOption, BarChartConfig, LineChartConfig, DonutPieChartConfig, NumberKpiChartConfig, TableChartConfig, ChartType, WidgetDefinitionConfig, } from './core/index.js';
3
+ export { BaseChartWidget, BarChartWidget, LineChartWidget, PieChartWidget, TableWidget, AnalyticsWidget, AnalyticsReport, } from './widgets/index.js';
4
+ export { DashboardContainer, EVENT_DASHBOARD_FILTER_CHANGE, EVENT_DASHBOARD_REFRESH, EVENT_DASHBOARD_LAYOUT_CHANGE, } from './dashboard/index.js';
5
+ export type { DashboardLayout, DashboardSlot, GridsterGridItem } from './dashboard/index.js';
6
+ export { AnalyticsFilterBar, AnalyticsFilterButton, AnalyticsWidgetToolbar } from './filters/index.js';
7
+ export { EVENT_FILTER_CHANGE, EVENT_FILTER_CLOSE, EVENT_FILTER_TOGGLE } from './filters/index.js';
8
+ export { AnalyticsDesigner } from './designer/index.js';
9
+ export type { DesignerWidgetOption } from './designer/index.js';
2
10
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -1 +1,6 @@
1
- export {};
1
+ export { setAnalyticsApiKey, getAnalyticsApiKey, buildWidgetDataUrl, fetchAnalyticsData, fetchWidgetData, } from './core/index.js';
2
+ export { BaseChartWidget, BarChartWidget, LineChartWidget, PieChartWidget, TableWidget, AnalyticsWidget, AnalyticsReport, } from './widgets/index.js';
3
+ export { DashboardContainer, EVENT_DASHBOARD_FILTER_CHANGE, EVENT_DASHBOARD_REFRESH, EVENT_DASHBOARD_LAYOUT_CHANGE, } from './dashboard/index.js';
4
+ export { AnalyticsFilterBar, AnalyticsFilterButton, AnalyticsWidgetToolbar } from './filters/index.js';
5
+ export { EVENT_FILTER_CHANGE, EVENT_FILTER_CLOSE, EVENT_FILTER_TOGGLE } from './filters/index.js';
6
+ export { AnalyticsDesigner } from './designer/index.js';