@keenmate/pure-admin-core 2.9.0-rc01 → 2.9.0-rc04

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 (36) hide show
  1. package/README.md +61 -14
  2. package/dist/css/main.css +748 -2
  3. package/package.json +3 -1
  4. package/snippets/buttons.html +51 -0
  5. package/snippets/cards.html +34 -4
  6. package/snippets/comparison.html +26 -22
  7. package/snippets/manifest.json +180 -115
  8. package/snippets/range-group.html +125 -0
  9. package/snippets/splitter.html +216 -0
  10. package/snippets/statistics.html +31 -0
  11. package/src/js/btn-split-auto-absorb.js +327 -0
  12. package/src/js/command-palette.js +472 -0
  13. package/src/js/file-selector.js +1275 -0
  14. package/src/js/internal/logging.js +121 -0
  15. package/src/js/logic-tree-renderer.js +303 -0
  16. package/src/js/modal-dialogs.js +460 -0
  17. package/src/js/overflow.js +371 -0
  18. package/src/js/pa-stat-fit.js +184 -0
  19. package/src/js/range-group.js +663 -0
  20. package/src/js/search-autocomplete-v2.js +907 -0
  21. package/src/js/search-autocomplete.js +434 -0
  22. package/src/js/settings-panel.js +245 -0
  23. package/src/js/split-button.js +141 -0
  24. package/src/js/splitter.js +1323 -0
  25. package/src/js/toast-service.js +302 -0
  26. package/src/js/tooltips-popovers.js +275 -0
  27. package/src/js/virtual-scroll.js +143 -0
  28. package/src/js/virtual-textbox.js +803 -0
  29. package/src/scss/_core.scss +10 -0
  30. package/src/scss/core-components/_buttons.scss +59 -0
  31. package/src/scss/core-components/_cards.scss +206 -0
  32. package/src/scss/core-components/_overflow.scss +50 -0
  33. package/src/scss/core-components/_range-group.scss +474 -0
  34. package/src/scss/core-components/_splitter.scss +206 -0
  35. package/src/scss/core-components/_statistics.scss +163 -0
  36. package/src/scss/variables/_components.scss +56 -2
@@ -118,6 +118,7 @@
118
118
  padding: $spacing-lg;
119
119
  min-height: $stat-square-min-size;
120
120
  min-width: $stat-square-min-size;
121
+ max-height: $stat-square-max-height; // keep full-width tiles from growing into page-dominating banners
121
122
  position: relative;
122
123
  border-radius: var(--pa-border-radius);
123
124
  box-shadow: $shadow-md;
@@ -183,6 +184,17 @@
183
184
  &.pa-stat--warning {
184
185
  background-color: var(--pa-warning-bg);
185
186
  color: var(--pa-btn-warning-text);
187
+
188
+ // Warning is the one square variant with DARK text (on a light amber
189
+ // surface). The number's default black text-shadow + drop-shadow stack is
190
+ // tuned for the white-text variants; against a dark glyph it has no
191
+ // contrast and smears into an "ink-blot" halo. Dial it to a whisper and
192
+ // drop the costly drop-shadow layer. Covers classic AND fit mode, since
193
+ // both render the number through .pa-stat__number.
194
+ .pa-stat__number {
195
+ text-shadow: 0 1px 1px rgba(0, 0, 0, $opacity-light);
196
+ filter: none;
197
+ }
186
198
  }
187
199
 
188
200
  &.pa-stat--danger {
@@ -194,6 +206,157 @@
194
206
  background-color: var(--pa-text-color-2);
195
207
  color: var(--pa-btn-primary-text);
196
208
  }
209
+
210
+ // ----------------------------------------------------------------
211
+ // FIT + PROGRESSIVE DISCLOSURE mode (opt-in: [data-pa-stat-fit])
212
+ // The number is sized to fill the tile by pa-stat-fit.js, which also
213
+ // wraps __number + __symbol into a __slot > __group at runtime. Lower-
214
+ // priority rows (label → change → context) reveal as the tile earns
215
+ // both width and height.
216
+ //
217
+ // REQUIRES A HEIGHT SOURCE on the tile (grid cell with a set height,
218
+ // explicit height, or aspect-ratio): container-type: size makes the
219
+ // box size independently of its content, so without a height it falls
220
+ // back to the $stat-square-min-size floor.
221
+ // ----------------------------------------------------------------
222
+ &[data-pa-stat-fit] {
223
+ container-type: size;
224
+ container-name: #{$stat-square-fit-container-name};
225
+ flex-direction: column;
226
+ flex-wrap: nowrap;
227
+ align-content: stretch;
228
+ align-items: stretch;
229
+ max-height: none; // fit height is container-driven; undo the base cap.
230
+ // min-height (the base $stat-square-min-size) stays as
231
+ // the default height when none is set + collapse floor.
232
+
233
+ // __slot grows to take the room not used by the metadata rows; the
234
+ // number is fit into it. ResizeObserver watches this element.
235
+ .pa-stat__slot {
236
+ flex: 1 1 auto;
237
+ min-height: 0;
238
+ display: flex;
239
+ align-items: center;
240
+ justify-content: flex-start;
241
+ }
242
+
243
+ // font-size is set inline (px) on __group by the JS; children scale via em.
244
+ .pa-stat__group {
245
+ display: inline-flex;
246
+ align-items: baseline;
247
+ column-gap: $stat-square-symbol-gap;
248
+ line-height: 1;
249
+ white-space: nowrap;
250
+ font-weight: $font-weight-bold;
251
+
252
+ .pa-stat__number { font-size: 1em; }
253
+ .pa-stat__symbol {
254
+ font-size: #{$stat-square-fit-symbol-ratio}em;
255
+ opacity: $stat-symbol-opacity;
256
+ }
257
+ }
258
+
259
+ // pa-stat-fit.js wraps the metadata rows into this column so the whole
260
+ // group can move beside the number in the horizontal (banner) layout.
261
+ // The number is the HERO; the metadata is subordinate — pa-stat-fit.js sets
262
+ // this column's font-size to a small fraction of the fitted number size
263
+ // (META_RATIO), so the rows below stay "supersmall" relative to the number at
264
+ // every tile size. The rows are em-relative so that one font-size cascades to
265
+ // all three. The value here is only the no-JS fallback.
266
+ .pa-stat__meta {
267
+ display: flex;
268
+ flex-direction: column;
269
+ min-width: 0; // let children ellipsis instead of overflowing
270
+ flex: 0 0 auto; // vertical layout: natural height below the slot
271
+ font-size: $stat-square-fit-meta-size; // JS overrides inline (px); this is the fallback
272
+ }
273
+
274
+ // metadata rows sit below the slot, each on its own line — all em-relative to
275
+ // __meta's (JS-driven) font-size so they scale with the hero number.
276
+ .pa-stat__label {
277
+ flex: 0 0 auto; // undo the base square's flex-basis:100%
278
+ margin-top: 0.35em;
279
+ font-size: 1em; // the meta base — the largest metadata line
280
+ }
281
+ .pa-stat__change {
282
+ flex: 0 0 auto;
283
+ margin-top: 0.35em;
284
+ font-size: 0.9em;
285
+ font-weight: $font-weight-semibold;
286
+ line-height: 1.2;
287
+ color: inherit; // default to the tile's text colour…
288
+ white-space: nowrap;
289
+ overflow: hidden;
290
+ text-overflow: ellipsis;
291
+
292
+ // …opt-in sentiment tints (same scale as the hero variant's __change)
293
+ &--positive { color: var(--pa-positive); }
294
+ &--neutral { color: var(--pa-neutral); }
295
+ &--negative { color: var(--pa-negative); }
296
+ }
297
+ .pa-stat__context {
298
+ flex: 0 0 auto;
299
+ margin-top: 0.35em;
300
+ font-size: 0.8em;
301
+ opacity: 0.7;
302
+ white-space: nowrap;
303
+ overflow: hidden;
304
+ text-overflow: ellipsis;
305
+ }
306
+
307
+ // ---- priority ladder: P0 number always; reveal P1–P4 with space ----
308
+ .pa-stat__symbol,
309
+ .pa-stat__label,
310
+ .pa-stat__change,
311
+ .pa-stat__context { display: none; }
312
+
313
+ @container #{$stat-square-fit-container-name} (min-width: #{$stat-square-fit-symbol-min-w}) and (min-height: #{$stat-square-fit-symbol-min-h}) {
314
+ .pa-stat__symbol { display: inline; }
315
+ }
316
+ @container #{$stat-square-fit-container-name} (min-width: #{$stat-square-fit-label-min-w}) and (min-height: #{$stat-square-fit-label-min-h}) {
317
+ .pa-stat__label { display: block; }
318
+ }
319
+ @container #{$stat-square-fit-container-name} (min-width: #{$stat-square-fit-change-min-w}) and (min-height: #{$stat-square-fit-change-min-h}) {
320
+ .pa-stat__change { display: block; }
321
+ }
322
+ @container #{$stat-square-fit-container-name} (min-width: #{$stat-square-fit-context-min-w}) and (min-height: #{$stat-square-fit-context-min-h}) {
323
+ .pa-stat__context { display: block; }
324
+ }
325
+
326
+ // ---- HORIZONTAL "banner" layout for wide tiles ----
327
+ // Toggled by pa-stat-fit.js (.pa-stat--fit-wide) when the tile is at least
328
+ // $stat-square-fit-horizontal-min-w wide. This CANNOT be a `@container`
329
+ // query: the tile is its own size container, and a container query only
330
+ // restyles a container's DESCENDANTS — never the container element itself,
331
+ // so the tile's own `flex-direction` would never flip. A JS class on the
332
+ // tile sidesteps that.
333
+ //
334
+ // Number on the LEFT (__slot is first in DOM → first flex item), filling
335
+ // the height so it stays big; the metadata column sits to its RIGHT,
336
+ // vertically centred. All meta rows are revealed here regardless of height
337
+ // — stacked beside the number they don't need vertical room — so a short
338
+ // wide banner still shows trend + context.
339
+ &.pa-stat--fit-wide {
340
+ flex-direction: row;
341
+ align-items: stretch;
342
+ column-gap: $spacing-lg;
343
+
344
+ .pa-stat__slot {
345
+ flex: 0 0 #{$stat-square-fit-number-width};
346
+ min-width: 0; // never let the number push past its column
347
+ justify-content: center; // centre the number within its column
348
+ }
349
+ .pa-stat__meta {
350
+ flex: 1 1 auto;
351
+ min-width: 0; // allow the rows to ellipsis
352
+ justify-content: center; // centre the rows vertically beside the number
353
+ }
354
+ .pa-stat__symbol { display: inline; }
355
+ .pa-stat__label,
356
+ .pa-stat__change,
357
+ .pa-stat__context { display: block; }
358
+ }
359
+ }
197
360
  }
198
361
  }
199
362
 
@@ -187,6 +187,11 @@ $card-tab-inline-padding-v: 0.3rem !default; // 3px - compact for header
187
187
  $card-tab-inline-padding-h: 0.8rem !default; // 8px
188
188
  $card-tab-hover-opacity: 0.1 !default;
189
189
 
190
+ // Responsive actions — header width below which the spread button list
191
+ // hides and the collapsed (split-button) form takes over. Default 28rem
192
+ // = 280px, which fits a 3-button action set comfortably.
193
+ $card-actions-collapse-at: 28rem !default;
194
+
190
195
  // ============================================================================
191
196
  // TABLE SYSTEM
192
197
  // ============================================================================
@@ -350,11 +355,43 @@ $stat-square-symbol-gap: 0.15em !default; // tight gap between number and symb
350
355
  // (~250–400px). Numbers are sized aggressively so the KPI reads as the dominant element.
351
356
  $stat-square-number-min: 3.2rem !default; // 32px floor
352
357
  $stat-square-number-scale: 25cqi !default; // 25% of tile width
353
- $stat-square-number-max: 9.6rem !default; // 96px ceiling (was 7.2/6.4bumped so wide tiles render large)
358
+ $stat-square-number-max: 7.2rem !default; // 72px ceiling (was 9.6 — full-width tiles hit the ceiling and read as oversized banners; 72px keeps a wide tile readable without dominating the page)
354
359
  // Symbol is intentionally smaller than the number (visual hierarchy: number primary, unit secondary).
355
360
  $stat-square-symbol-min: 1.6rem !default; // 16px floor (~50% of number-min)
356
361
  $stat-square-symbol-scale: 12cqi !default; // 12% of tile width (~48% of number)
357
- $stat-square-symbol-max: 4.8rem !default; // 48px ceiling (~50% of number-max)
362
+ $stat-square-symbol-max: 3.6rem !default; // 36px ceiling (~50% of number-max, was 4.8)
363
+
364
+ // Guard so a very wide tile (e.g. one square per full-width row instead of in a
365
+ // 1/3 KPI column) can't grow into a page-dominating block. Caps how tall the
366
+ // flex layout gets before the label is pushed to the bottom edge.
367
+ $stat-square-max-height: 16rem !default; // 160px
368
+
369
+ // Stat square FIT mode (opt-in via [data-pa-stat-fit]) — progressive disclosure.
370
+ // The number is sized to fill the box by pa-stat-fit.js (ResizeObserver); the
371
+ // lower-priority rows reveal as the tile earns BOTH enough width and height.
372
+ // NB: @container does NOT auto-interpolate Sass vars (unlike @media) — these
373
+ // must be emitted with #{} in the rules. Gated on width AND height so a
374
+ // wide-but-short banner doesn't reveal the tall-only tiers.
375
+ $stat-square-fit-container-name: pa-stat !default;
376
+ $stat-square-fit-meta-size: $font-size-xs !default; // no-JS fallback for the metadata
377
+ // column; pa-stat-fit.js overrides it
378
+ // inline with META_RATIO × number size
379
+ $stat-square-fit-symbol-ratio: 0.5 !default; // symbol = 0.5em of the number
380
+ $stat-square-fit-symbol-min-w: 8rem !default; // P1 symbol reveals at…
381
+ $stat-square-fit-symbol-min-h: 4.5rem !default;
382
+ $stat-square-fit-label-min-w: 13rem !default; // P2 label
383
+ $stat-square-fit-label-min-h: 6.5rem !default;
384
+ $stat-square-fit-change-min-w: 18rem !default; // P3 trend
385
+ $stat-square-fit-change-min-h: 9.5rem !default;
386
+ $stat-square-fit-context-min-w: 24rem !default; // P4 context
387
+ $stat-square-fit-context-min-h: 13rem !default;
388
+
389
+ // Horizontal "banner" arrangement: on wide tiles the number moves to the left
390
+ // (filling the height) and the metadata stacks in a column to its right, so the
391
+ // number stays dominant and the width isn't wasted. Auto-switches once the tile
392
+ // is at least this wide (plain width query — broadest engine support).
393
+ $stat-square-fit-horizontal-min-w: 32rem !default; // ≥ this wide → horizontal banner
394
+ $stat-square-fit-number-width: 44% !default; // number column share in horizontal
358
395
 
359
396
  // Stat shadow values
360
397
  $stat-text-shadow-1-y: 4px !default;
@@ -772,3 +809,20 @@ $bar-list-bar-bg: rgba(0, 0, 0, 0.06) !default;
772
809
  $bar-list-label-font-size: $font-size-sm !default;
773
810
  $bar-list-value-font-size: $font-size-sm !default;
774
811
  $bar-list-value-font-weight: $font-weight-semibold !default;
812
+
813
+ // ============================================================================
814
+ // SPLITTER SYSTEM
815
+ // ============================================================================
816
+ $splitter-gutter-size: 0.6rem !default; // 6px gutter thickness
817
+ $splitter-gutter-bg: rgba(128, 128, 128, 0.08) !default;
818
+ $splitter-gutter-hover-bg: rgba(128, 128, 128, 0.18) !default;
819
+ $splitter-gutter-active-bg: rgba($accent-color, 0.35) !default; // mid-drag
820
+ $splitter-gutter-grip-length: 2.4rem !default; // 24px grip indicator
821
+ $splitter-gutter-grip-thickness: 2px !default;
822
+ $splitter-gutter-grip-color: rgba(128, 128, 128, 0.45) !default;
823
+ $splitter-gutter-grip-hover-color: $accent-color !default;
824
+ $splitter-focus-ring-color: rgba($accent-color, 0.4) !default;
825
+ $splitter-focus-ring-width: 2px !default;
826
+ $splitter-transition: background-color 0.15s ease !default;
827
+ $splitter-pane-min-size: 0 !default; // absolute floor regardless of constraints
828
+ $splitter-rail-size: 4rem !default; // 40px — start pane width when minimized to rail