@aquera/nile-visualization 2.9.8 → 2.9.9

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.
@@ -8,6 +8,13 @@ export declare class NileFilterChart extends NileElement implements FilterChartH
8
8
  /** When set, the host (e.g. nile-chart) is already rendering the control's label/description
9
9
  * in its own header — skip the in-body copies to avoid duplication. */
10
10
  hideControlHeaders: boolean;
11
+ /**
12
+ * Visual appearance. `'minimal'` collapses control padding to 6px for
13
+ * compact layouts; default (`'default'` or omitted) keeps the standard
14
+ * 16px / 20px. Set via the reflected `appearance` attribute, the
15
+ * `.appearance` property, or `config.chart.appearance`.
16
+ */
17
+ appearance: 'default' | 'minimal';
11
18
  selectedValues: Map<string, unknown>;
12
19
  private collapsedGroups;
13
20
  /** Currently displayed (animated) placeholder text per prompt-variant control id. */
@@ -21,8 +28,17 @@ export declare class NileFilterChart extends NileElement implements FilterChartH
21
28
  /** Id of the prompt control whose input currently has focus (drives the
22
29
  * nile-dropdown panel open state). null when no prompt is focused. */
23
30
  promptFocusedId: string | null;
24
- /** Active typewriter timers per prompt control id (so we can stop them). */
31
+ /** Pixel width of each prompt control's bordered field kept in sync with
32
+ * the rendered `.fc-prompt__field` via a ResizeObserver attached in
33
+ * prompt.ts. Consumed by the suggestion tooltip so its popup matches the
34
+ * input box width and wraps long content onto multiple lines. */
35
+ promptFieldWidth: Map<string, number>;
36
+ /** Active rtypewiter timers per prompt control id (so we can stop them). */
25
37
  private _promptTimers;
38
+ /** Per-control typewriter tick fn — retained so the animation can be resumed
39
+ * from its preserved closure state (phrase index, char index, deleting flag)
40
+ * after a pause-at-rest-point. */
41
+ private _promptTickFns;
26
42
  /** Compiled filtrex predicates per prompt control id (strict-mode successes). */
27
43
  private _promptEvaluators;
28
44
  /** Parsed AST per prompt control id (strict-mode successes). */
@@ -60,6 +76,7 @@ export declare class NileFilterChart extends NileElement implements FilterChartH
60
76
  submitPrompt(ctrl: NormalizedFilterControl): void;
61
77
  setPromptActiveIndex(id: string, idx: number): void;
62
78
  setPromptFocused(id: string, focused: boolean): void;
79
+ setPromptFieldWidth(id: string, width: number): void;
63
80
  private _validateOrClear;
64
81
  private _clearPromptValidation;
65
82
  private _syncPromptAnimations;
@@ -80,8 +97,8 @@ export declare class NileFilterChart extends NileElement implements FilterChartH
80
97
  private _renderControl;
81
98
  /**
82
99
  * If any prompt control in `controls` has its toggle enabled and is currently
83
- * in NQL mode, collapse the visible set down to just that prompt — Basic mode
84
- * shows everything, JQL mode shows only the expression input.
100
+ * in Expression mode, collapse the visible set down to just that prompt —
101
+ * Prompt mode shows everything, Expression mode shows only the expression input.
85
102
  */
86
103
  private _filterByPromptMode;
87
104
  private _renderGroup;
@@ -24,6 +24,13 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
24
24
  /** When set, the host (e.g. nile-chart) is already rendering the control's label/description
25
25
  * in its own header — skip the in-body copies to avoid duplication. */
26
26
  this.hideControlHeaders = false;
27
+ /**
28
+ * Visual appearance. `'minimal'` collapses control padding to 6px for
29
+ * compact layouts; default (`'default'` or omitted) keeps the standard
30
+ * 16px / 20px. Set via the reflected `appearance` attribute, the
31
+ * `.appearance` property, or `config.chart.appearance`.
32
+ */
33
+ this.appearance = 'default';
27
34
  this.selectedValues = new Map();
28
35
  this.collapsedGroups = new Set();
29
36
  /** Currently displayed (animated) placeholder text per prompt-variant control id. */
@@ -37,8 +44,17 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
37
44
  /** Id of the prompt control whose input currently has focus (drives the
38
45
  * nile-dropdown panel open state). null when no prompt is focused. */
39
46
  this.promptFocusedId = null;
40
- /** Active typewriter timers per prompt control id (so we can stop them). */
47
+ /** Pixel width of each prompt control's bordered field kept in sync with
48
+ * the rendered `.fc-prompt__field` via a ResizeObserver attached in
49
+ * prompt.ts. Consumed by the suggestion tooltip so its popup matches the
50
+ * input box width and wraps long content onto multiple lines. */
51
+ this.promptFieldWidth = new Map();
52
+ /** Active rtypewiter timers per prompt control id (so we can stop them). */
41
53
  this._promptTimers = new Map();
54
+ /** Per-control typewriter tick fn — retained so the animation can be resumed
55
+ * from its preserved closure state (phrase index, char index, deleting flag)
56
+ * after a pause-at-rest-point. */
57
+ this._promptTickFns = new Map();
42
58
  /** Compiled filtrex predicates per prompt control id (strict-mode successes). */
43
59
  this._promptEvaluators = new Map();
44
60
  /** Parsed AST per prompt control id (strict-mode successes). */
@@ -71,6 +87,9 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
71
87
  this._normalizeIds();
72
88
  this._initValues();
73
89
  this._syncPromptAnimations();
90
+ const cfgAppearance = this.config?.chart?.appearance;
91
+ if (cfgAppearance === 'minimal' || cfgAppearance === 'default')
92
+ this.appearance = cfgAppearance;
74
93
  }
75
94
  // Keep portaled suggestion panels in sync with the latest panel content.
76
95
  // nile-dropdown clones the panel once at open-time and never re-clones,
@@ -125,6 +144,10 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
125
144
  clearTimeout(pending);
126
145
  this._promptDebounce.delete(ctrl.id);
127
146
  }
147
+ if (this._promptTimers.has(ctrl.id)) {
148
+ this._stopPromptAnimation(ctrl.id);
149
+ this._startPromptAnimation(ctrl);
150
+ }
128
151
  const value = String(this.selectedValues.get(ctrl.id) ?? '');
129
152
  this._validateOrClear(ctrl, value, { explicit: true });
130
153
  }
@@ -147,13 +170,42 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
147
170
  setPromptFocused(id, focused) {
148
171
  if (focused) {
149
172
  this.promptFocusedId = id;
173
+ const t = this._promptTimers.get(id);
174
+ if (t) {
175
+ clearTimeout(t);
176
+ this._promptTimers.delete(id);
177
+ }
178
+ if (this.promptPlaceholder.get(id) !== '') {
179
+ this.promptPlaceholder = new Map(this.promptPlaceholder).set(id, '');
180
+ }
150
181
  }
151
182
  else if (this.promptFocusedId === id) {
152
183
  this.promptFocusedId = null;
184
+ // Resume from the preserved closure state. Guard against re-entry: if
185
+ // a timer somehow exists (shouldn't, but defensive), don't double-tick.
186
+ const tickFn = this._promptTickFns.get(id);
187
+ if (tickFn && !this._promptTimers.has(id)) {
188
+ tickFn();
189
+ }
190
+ }
191
+ }
192
+ setPromptFieldWidth(id, width) {
193
+ const rounded = Math.round(width);
194
+ if (this.promptFieldWidth.get(id) === rounded)
195
+ return;
196
+ this.promptFieldWidth = new Map(this.promptFieldWidth).set(id, rounded);
197
+ // Tippy popups are portaled to document.body so component-scoped styles
198
+ // can't reach them, and nile-lite-tooltip's `maxWidth` only takes effect
199
+ // at attach time (its updated() hook doesn't re-attach for maxWidth
200
+ // changes). Mirror the live width onto a document-level CSS variable
201
+ // the global .tippy-box rule reads — wrapping then always reflects
202
+ // the current input width.
203
+ if (typeof document !== 'undefined') {
204
+ document.documentElement.style.setProperty('--fc-prompt-tooltip-max-width', `${rounded}px`);
153
205
  }
154
206
  }
155
207
  _validateOrClear(ctrl, value, opts = {}) {
156
- const isNql = this.promptModes.get(ctrl.id) === 'nql';
208
+ const isNql = this.promptModes.get(ctrl.id) === 'expression';
157
209
  if (value.trim() === '') {
158
210
  this._clearPromptValidation(ctrl.id);
159
211
  this._emitChange();
@@ -187,7 +239,6 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
187
239
  // expressions); NQL surfaces them so the user sees what's wrong.
188
240
  const errs = new Map(this.promptErrors);
189
241
  if (isNql) {
190
- console.error(`[nile-filter-chart] "${ctrl.id}" parse error:`, error.message);
191
242
  errs.set(ctrl.id, error.message);
192
243
  }
193
244
  else {
@@ -213,7 +264,7 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
213
264
  _syncPromptAnimations() {
214
265
  const wanted = new Set();
215
266
  for (const ctrl of this._flatControls()) {
216
- if (ctrl.variant === 'prompt') {
267
+ if (ctrl.variant === 'prompt' || ctrl.variant === 'hybrid' || ctrl.variant === 'expression') {
217
268
  wanted.add(ctrl.id);
218
269
  if (!this._promptTimers.has(ctrl.id))
219
270
  this._startPromptAnimation(ctrl);
@@ -226,9 +277,18 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
226
277
  }
227
278
  }
228
279
  _startPromptAnimation(ctrl) {
229
- const phrases = ctrl.placeholders && ctrl.placeholders.length
230
- ? ctrl.placeholders
231
- : ['Ask anything…'];
280
+ const getPhrases = () => {
281
+ const mode = this.promptModes.get(ctrl.id);
282
+ if (ctrl.variant === 'hybrid' || ctrl.variant === 'expression') {
283
+ if (mode === 'expression' && ctrl.expressionPlaceholders?.length)
284
+ return ctrl.expressionPlaceholders;
285
+ if (mode === 'prompt' && ctrl.promptPlaceholders?.length)
286
+ return ctrl.promptPlaceholders;
287
+ }
288
+ return ctrl.placeholders && ctrl.placeholders.length
289
+ ? ctrl.placeholders
290
+ : ['Ask anything…'];
291
+ };
232
292
  const typeSpeed = ctrl.typeSpeedMs ?? 60;
233
293
  const pauseAfterType = ctrl.pauseBeforeDeleteMs ?? 1400;
234
294
  const pauseBetween = ctrl.pauseBetweenMs ?? 400;
@@ -236,6 +296,9 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
236
296
  let charIdx = 0;
237
297
  let deleting = false;
238
298
  const tick = () => {
299
+ const phrases = getPhrases();
300
+ if (phraseIdx >= phrases.length)
301
+ phraseIdx = 0;
239
302
  const phrase = phrases[phraseIdx];
240
303
  let nextDelay;
241
304
  if (!deleting) {
@@ -265,15 +328,18 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
265
328
  }
266
329
  this._promptTimers.set(ctrl.id, setTimeout(tick, nextDelay));
267
330
  };
268
- // Kick it off
331
+ this._promptTickFns.set(ctrl.id, tick);
269
332
  this.promptPlaceholder = new Map(this.promptPlaceholder).set(ctrl.id, '');
270
- this._promptTimers.set(ctrl.id, setTimeout(tick, 100));
333
+ if (this.promptFocusedId !== ctrl.id) {
334
+ this._promptTimers.set(ctrl.id, setTimeout(tick, 100));
335
+ }
271
336
  }
272
337
  _stopPromptAnimation(id) {
273
338
  const t = this._promptTimers.get(id);
274
339
  if (t)
275
340
  clearTimeout(t);
276
341
  this._promptTimers.delete(id);
342
+ this._promptTickFns.delete(id);
277
343
  const next = new Map(this.promptPlaceholder);
278
344
  next.delete(id);
279
345
  this.promptPlaceholder = next;
@@ -357,8 +423,8 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
357
423
  || ctrl.variant === 'expression'
358
424
  || ctrl.variant === 'hybrid') {
359
425
  const initialMode = ctrl.variant === 'expression'
360
- ? 'nql'
361
- : (ctrl.queryLanguage?.mode ?? 'strict') === 'strict' ? 'nql' : 'basic';
426
+ ? 'expression'
427
+ : (ctrl.queryLanguage?.mode ?? 'strict') === 'strict' ? 'expression' : 'prompt';
362
428
  modes.set(ctrl.id, initialMode);
363
429
  }
364
430
  if (ctrl.value !== undefined) {
@@ -403,12 +469,12 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
403
469
  this.selectedValues.forEach((val, id) => {
404
470
  // Prompt controls in NQL mode with a successful parse emit the
405
471
  // structured `{ source, ast }` payload so downstream consumers get
406
- // both the typed text and the parsed shape. Basic mode (and NQL
472
+ // both the typed text and the parsed shape. Prompt mode (and Expression
407
473
  // pre-validation / parse-failure) emit the raw string — the same
408
474
  // shape every other variant uses.
409
475
  const mode = this.promptModes.get(id);
410
476
  const ast = this._promptAsts.get(id);
411
- if (mode === 'nql' && ast && typeof val === 'string' && val.trim() !== '') {
477
+ if (mode === 'expression' && ast && typeof val === 'string' && val.trim() !== '') {
412
478
  filters[id] = { source: val, ast };
413
479
  }
414
480
  else {
@@ -422,13 +488,13 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
422
488
  detail.errors = errors;
423
489
  }
424
490
  if (this._promptEvaluators.size > 0) {
425
- // Only surface evaluators for controls whose active mode is NQL.
426
- // In Basic / Prompt mode the consumer expects a plain-string payload
427
- // — leaking the cached evaluator from the last NQL pass would lie
428
- // about what the user has selected.
491
+ // Only surface evaluators for controls whose active mode is Expression.
492
+ // In Prompt mode the consumer expects a plain-string payload — leaking
493
+ // the cached evaluator from the last Expression pass would lie about
494
+ // what the user has selected.
429
495
  const evaluators = {};
430
496
  this._promptEvaluators.forEach((fn, id) => {
431
- if (this.promptModes.get(id) === 'nql')
497
+ if (this.promptModes.get(id) === 'expression')
432
498
  evaluators[id] = fn;
433
499
  });
434
500
  if (Object.keys(evaluators).length > 0)
@@ -488,8 +554,8 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
488
554
  enabled: true,
489
555
  mode: ctrl.queryLanguage?.mode ?? 'strict',
490
556
  toggle: {
491
- basic: { label: ctrl.queryLanguage?.toggle?.basic?.label ?? 'Prompt' },
492
- nql: { label: ctrl.queryLanguage?.toggle?.nql?.label ?? 'Expression' },
557
+ prompt: { label: ctrl.queryLanguage?.toggle?.prompt?.label ?? 'Prompt' },
558
+ expression: { label: ctrl.queryLanguage?.toggle?.expression?.label ?? 'Expression' },
493
559
  },
494
560
  },
495
561
  });
@@ -506,15 +572,15 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
506
572
  }
507
573
  /**
508
574
  * If any prompt control in `controls` has its toggle enabled and is currently
509
- * in NQL mode, collapse the visible set down to just that prompt — Basic mode
510
- * shows everything, JQL mode shows only the expression input.
575
+ * in Expression mode, collapse the visible set down to just that prompt —
576
+ * Prompt mode shows everything, Expression mode shows only the expression input.
511
577
  */
512
578
  _filterByPromptMode(controls) {
513
- const nqlPrompt = controls.find(c => ((c.variant === 'prompt' && c.queryLanguage?.enabled)
579
+ const expressionPrompt = controls.find(c => ((c.variant === 'prompt' && c.queryLanguage?.enabled)
514
580
  || c.variant === 'hybrid'
515
581
  || c.variant === 'expression')
516
- && this.promptModes.get(c.id) === 'nql');
517
- return nqlPrompt ? [nqlPrompt] : controls;
582
+ && this.promptModes.get(c.id) === 'expression');
583
+ return expressionPrompt ? [expressionPrompt] : controls;
518
584
  }
519
585
  _renderGroup(group) {
520
586
  const collapsed = this.collapsedGroups.has(group.label);
@@ -573,6 +639,9 @@ __decorate([
573
639
  __decorate([
574
640
  property({ type: Boolean, attribute: 'hide-control-headers', reflect: true })
575
641
  ], NileFilterChart.prototype, "hideControlHeaders", void 0);
642
+ __decorate([
643
+ property({ type: String, reflect: true })
644
+ ], NileFilterChart.prototype, "appearance", void 0);
576
645
  __decorate([
577
646
  state()
578
647
  ], NileFilterChart.prototype, "selectedValues", void 0);
@@ -594,6 +663,9 @@ __decorate([
594
663
  __decorate([
595
664
  state()
596
665
  ], NileFilterChart.prototype, "promptFocusedId", void 0);
666
+ __decorate([
667
+ state()
668
+ ], NileFilterChart.prototype, "promptFieldWidth", void 0);
597
669
  NileFilterChart = NileFilterChart_1 = __decorate([
598
670
  customElement('nile-filter-chart')
599
671
  ], NileFilterChart);