mgv-backoffice 1.33.0 → 1.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -2
- package/dist/components/BaseCodeBlock.vue.d.ts +17 -0
- package/dist/components/BasePillPickerModal.vue.d.ts +43 -0
- package/dist/components/BaseToolbarButton.vue.d.ts +1 -1
- package/dist/composables/usePolling.d.ts +31 -0
- package/dist/composables/useThemeClasses.d.ts +27 -24
- package/dist/index.d.ts +7 -1
- package/dist/types/pillPicker.d.ts +14 -0
- package/dist/ui-lib.css +1 -1
- package/dist/ui-lib.js +825 -609
- package/dist/ui-lib.umd.cjs +1 -1
- package/dist/utils/format.d.ts +12 -0
- package/dist/utils/validate.d.ts +35 -0
- package/package.json +1 -1
- package/src/components/BaseCodeBlock.test.ts +70 -0
- package/src/components/BaseCodeBlock.vue +74 -0
- package/src/components/BasePillPickerModal.test.ts +95 -0
- package/src/components/BasePillPickerModal.vue +0 -0
- package/src/components/BaseToolbarButton.test.ts +48 -0
- package/src/components/BaseToolbarButton.vue +21 -6
- package/src/composables/usePolling.test.ts +112 -0
- package/src/composables/usePolling.ts +90 -0
- package/src/composables/useThemeClasses.test.ts +34 -0
- package/src/composables/useThemeClasses.ts +30 -26
- package/src/index.ts +13 -0
- package/src/types/pillPicker.ts +14 -0
- package/src/utils/format.test.ts +29 -0
- package/src/utils/format.ts +28 -0
- package/src/utils/validate.test.ts +82 -0
- package/src/utils/validate.ts +76 -0
package/README.md
CHANGED
|
@@ -669,6 +669,24 @@ Consistency checks for dynamic key/value grids (header lists, query params,
|
|
|
669
669
|
metadata rows). Rows with `matcherType: 'absent'` are exempt — an absent
|
|
670
670
|
matcher intentionally carries no value.
|
|
671
671
|
|
|
672
|
+
### Input validators
|
|
673
|
+
|
|
674
|
+
```ts
|
|
675
|
+
import { isValidAbsoluteUrl, isValidJson, isValidXml, isValidBase64 } from 'mgv-backoffice'
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
Pure, dependency-free form-input validators. The payload validators treat
|
|
679
|
+
empty/whitespace-only input as **valid** — required-ness is a separate rule
|
|
680
|
+
from well-formedness; `isValidAbsoluteUrl` validates a value that must exist,
|
|
681
|
+
so empty is invalid there.
|
|
682
|
+
|
|
683
|
+
| Function | Signature | Returns |
|
|
684
|
+
| -------------------- | ---------------------------- | ------- |
|
|
685
|
+
| `isValidAbsoluteUrl` | `(value: string) => boolean` | `true` for an absolute `http://` / `https://` URL (other schemes rejected). |
|
|
686
|
+
| `isValidJson` | `(str: string) => boolean` | `true` when empty or parseable as JSON. |
|
|
687
|
+
| `isValidXml` | `(str: string) => boolean` | `true` when empty or well-formed XML (DOMParser `<parsererror>` check; browser-only). |
|
|
688
|
+
| `isValidBase64` | `(str: string) => boolean` | `true` when empty or well-formed base64 (whitespace stripped, length/alphabet checked, then `atob` as the final authority). |
|
|
689
|
+
|
|
672
690
|
### HTML sanitizer
|
|
673
691
|
|
|
674
692
|
```ts
|
|
@@ -724,6 +742,8 @@ API values can be passed without pre-sanitising.
|
|
|
724
742
|
| `fmtPrice` | `(n: number) => string` | Price with precision that scales to magnitude (more decimals for sub-cent values). |
|
|
725
743
|
| `fmtPct` | `(n: number, digits = 2) => string` | Percentage with explicit sign, e.g. `"+2.50%"`. |
|
|
726
744
|
| `fmtUsd` | `(v: number) => string` | Signed USD amount with leading sign, e.g. `"+$5.00"`. |
|
|
745
|
+
| `formatJson` | `(content: string) => string` | Pretty-prints parseable JSON with 2-space indentation; returns anything else verbatim. |
|
|
746
|
+
| `stringifyValue` | `(value: unknown) => string` | Display string for an unknown value: strings pass through, null/undefined → `''`, everything else JSON-serialized (`String()` fallback). |
|
|
727
747
|
|
|
728
748
|
### Spec-form helpers
|
|
729
749
|
|
|
@@ -1106,7 +1126,7 @@ a page header. Optional leading icon (via slot) plus a label.
|
|
|
1106
1126
|
| Prop | Type | Default | Description |
|
|
1107
1127
|
| ---------- | --------- | ----------- | ----------- |
|
|
1108
1128
|
| `label` | `String` | `''` | Button text. Omit for an icon-only button. |
|
|
1109
|
-
| `variant` | `String` | `'neutral'` | `'neutral'` (grey)
|
|
1129
|
+
| `variant` | `String` | `'neutral'` | `'neutral'` (grey), `'danger'` (solid red) or `'ghost'` (slate h-9 outline — toolbar/modal-footer buttons). |
|
|
1110
1130
|
| `disabled` | `Boolean` | `false` | Greys out and blocks the click. |
|
|
1111
1131
|
| `title` | `String` | `undefined` | Native tooltip / a11y text. |
|
|
1112
1132
|
| `type` | `String` | `'button'` | Native button type. |
|
|
@@ -1304,6 +1324,26 @@ selection, so picking the same file twice still emits.
|
|
|
1304
1324
|
/>
|
|
1305
1325
|
```
|
|
1306
1326
|
|
|
1327
|
+
### BaseCodeBlock
|
|
1328
|
+
|
|
1329
|
+
Themed monospace `<pre>` for JSON payloads, request dumps and code snippets
|
|
1330
|
+
(extracted from WireMate's stub/request detail views). Preserves whitespace
|
|
1331
|
+
verbatim, scrolls both axes, and adapts to the theme. Extra classes (margins
|
|
1332
|
+
etc.) fall through via the normal class merge.
|
|
1333
|
+
|
|
1334
|
+
**Props:**
|
|
1335
|
+
|
|
1336
|
+
| Prop | Type | Default | Description |
|
|
1337
|
+
| ---------------- | -------- | -------- | ----------- |
|
|
1338
|
+
| `code` | `String` | **required** | The raw text to render. |
|
|
1339
|
+
| `variant` | `String` | `'soft'` | `'soft'` = tinted fill, no border (in-card look); `'bordered'` = bordered card fill (standalone look). |
|
|
1340
|
+
| `size` | `String` | `'sm'` | `'sm'` = `text-sm px-5 py-4`; `'xs'` = dense `text-xs p-3`. |
|
|
1341
|
+
| `maxHeightClass` | `String` | `''` | Optional Tailwind max-height utility, e.g. `max-h-96`. |
|
|
1342
|
+
|
|
1343
|
+
```vue
|
|
1344
|
+
<BaseCodeBlock :code="formatJson(response.body)" size="xs" max-height-class="max-h-64" />
|
|
1345
|
+
```
|
|
1346
|
+
|
|
1307
1347
|
---
|
|
1308
1348
|
|
|
1309
1349
|
## Forms & tables
|
|
@@ -1533,6 +1573,46 @@ content at the card's bottom.
|
|
|
1533
1573
|
|
|
1534
1574
|
---
|
|
1535
1575
|
|
|
1576
|
+
### BasePillPickerModal
|
|
1577
|
+
|
|
1578
|
+
"Pick one of many" modal: every item rendered as a clickable pill, narrowed
|
|
1579
|
+
by a free-text filter and an optional segmented group toggle. Clicking a pill
|
|
1580
|
+
emits `pick` with the item; backdrop / Escape / the footer Close emit `close`.
|
|
1581
|
+
Narrowing state lives inside, so a `v-if`-mounted instance always opens fresh.
|
|
1582
|
+
|
|
1583
|
+
**Props:** `title` + `items: PillPickerItem[]` (required);
|
|
1584
|
+
`groups?: SegmentedOption<string>[]` (renders the group toggle with an
|
|
1585
|
+
`allLabel` option prepended, narrowing by each item's `group`); `icon?`
|
|
1586
|
+
(defaults to the magnifying glass), `subtitle?`, `searchPlaceholder`,
|
|
1587
|
+
`emptyMessage`, `noMatchMessage`, `mono` (mono font for the filter input and
|
|
1588
|
+
pills — symbols, codes, ids), `maxWidthClass` (default `max-w-2xl`),
|
|
1589
|
+
`closeText`, `groupAriaLabel`, `allLabel`.
|
|
1590
|
+
|
|
1591
|
+
**Emits:** `pick(item: PillPickerItem)`, `close`.
|
|
1592
|
+
|
|
1593
|
+
```ts
|
|
1594
|
+
interface PillPickerItem {
|
|
1595
|
+
id: string // unique key; identifies the pick
|
|
1596
|
+
label: string // pill text; what the filter matches
|
|
1597
|
+
group?: string // segmented-toggle bucket
|
|
1598
|
+
title?: string // pill tooltip
|
|
1599
|
+
}
|
|
1600
|
+
```
|
|
1601
|
+
|
|
1602
|
+
```vue
|
|
1603
|
+
<BasePillPickerModal
|
|
1604
|
+
v-if="open"
|
|
1605
|
+
title="Symbols"
|
|
1606
|
+
:items="symbols.map(s => ({ id: s.id, label: s.symbol, group: s.assetClass }))"
|
|
1607
|
+
:groups="[{ value: 'STOCK', label: 'STOCK' }, { value: 'CRYPTO', label: 'CRYPTO' }]"
|
|
1608
|
+
mono
|
|
1609
|
+
@pick="apply"
|
|
1610
|
+
@close="open = false"
|
|
1611
|
+
/>
|
|
1612
|
+
```
|
|
1613
|
+
|
|
1614
|
+
---
|
|
1615
|
+
|
|
1536
1616
|
## Composables
|
|
1537
1617
|
|
|
1538
1618
|
```ts
|
|
@@ -1548,6 +1628,7 @@ import {
|
|
|
1548
1628
|
useNotifications,
|
|
1549
1629
|
useQueryParamSync,
|
|
1550
1630
|
useFieldClasses,
|
|
1631
|
+
usePolling,
|
|
1551
1632
|
} from 'mgv-backoffice'
|
|
1552
1633
|
```
|
|
1553
1634
|
|
|
@@ -1555,7 +1636,7 @@ import {
|
|
|
1555
1636
|
| ---------- | ------- |
|
|
1556
1637
|
| `initTheme({ storageKey? })` | Explicitly initialize the theme singleton. Call in your app entry point **before mounting** when you need a custom storage key — library components call `useTheme()` internally, so a component mounting first would otherwise lock in the default key (a dev-mode warning fires if that happens). |
|
|
1557
1638
|
| `useTheme({ storageKey? })` | Singleton dark/light controller. Toggles `<html class="dark">` and persists via localStorage (default key `'mgv-theme'`). Prefer `initTheme` at app entry for custom keys. |
|
|
1558
|
-
| `useThemeClasses()` | Named Tailwind class roles for dark/light (card, border, primaryText, mutedText, dimText, input, ghostButton, emeraldText, redText, …).
|
|
1639
|
+
| `useThemeClasses()` | Named Tailwind class roles for dark/light (card, border, primaryText, mutedText, dimText, input, ghostButton, emeraldText, redText, …). Since 1.34.0 returns a `reactive` object of plain strings — bind `t.card` directly, never `t.card.value` (the old ComputedRef shape leaked ref internals into `:class` bindings). |
|
|
1559
1640
|
| `useEscapeKey(handler)` | Component-scoped Escape key listener. |
|
|
1560
1641
|
| `useDebouncedRef(source, delay?)` | Debounced mirror of a ref. Timer cleared on scope dispose. |
|
|
1561
1642
|
| `useToast(durationMs?)` | Per-component toast state: `{ showToast, toastMessage, toastType, showToastMessage }`. |
|
|
@@ -1564,6 +1645,7 @@ import {
|
|
|
1564
1645
|
| `useNotifications()` | Singleton notification state shared by the sidebar bell and `BaseNotificationPanel`: `{ notifications, unreadCount, open, openPanel, closePanel, togglePanel, setNotifications, add, remove, markRead, markAllRead, clear }`. |
|
|
1565
1646
|
| `useQueryParamSync()` | URL-query mirroring for filterable views: `{ qparam(name), qenum(name, allowed, fallback), replaceQuery(next) }`. Read filters from the query string once on setup, write changes back with `router.replace` (no-op when unchanged) so filtered views stay shareable without polluting history. |
|
|
1566
1647
|
| `useFieldClasses()` | Shared form-field class strings for the gray/emerald form skin: `{ label, input, requiredInput(value) }`. `requiredInput` returns a red border+ring skin while the value is empty and the standard skin otherwise. |
|
|
1648
|
+
| `usePolling(fn, intervalMs, { immediate?, pauseWhenHidden? })` | Visibility-gated polling loop bound to the component lifecycle: starts on mount, stops on unmount, pauses while the tab is hidden and refreshes + resumes on return to visible (both default on). Pass `intervalMs: null` for refresh-only mode (run on mount + each return-to-visible, no timer). Returns `{ start, stop, active }`. Catch errors inside `fn` — the loop never swallows rejections. |
|
|
1567
1649
|
|
|
1568
1650
|
---
|
|
1569
1651
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
/** The raw text to render. Whitespace is preserved verbatim. */
|
|
3
|
+
code: string;
|
|
4
|
+
/** Visual style: tinted fill ('soft') or bordered card ('bordered'). */
|
|
5
|
+
variant?: 'soft' | 'bordered';
|
|
6
|
+
/** Text size + padding: 'sm' (roomy) or 'xs' (dense). */
|
|
7
|
+
size?: 'sm' | 'xs';
|
|
8
|
+
/** Optional Tailwind max-height utility, e.g. 'max-h-96'. */
|
|
9
|
+
maxHeightClass?: string;
|
|
10
|
+
};
|
|
11
|
+
declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
12
|
+
size: "sm" | "xs";
|
|
13
|
+
variant: "soft" | "bordered";
|
|
14
|
+
maxHeightClass: string;
|
|
15
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
16
|
+
declare const _default: typeof __VLS_export;
|
|
17
|
+
export default _default;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Component } from 'vue';
|
|
2
|
+
import { PillPickerItem } from '../types/pillPicker';
|
|
3
|
+
import { SegmentedOption } from '../types/segmented';
|
|
4
|
+
interface Props {
|
|
5
|
+
title: string;
|
|
6
|
+
items: PillPickerItem[];
|
|
7
|
+
/**
|
|
8
|
+
* Group toggle rendered next to the text filter. When set, an "All"
|
|
9
|
+
* option is prepended and pills are narrowed by their `group` field.
|
|
10
|
+
*/
|
|
11
|
+
groups?: SegmentedOption<string>[];
|
|
12
|
+
/** Icon for the modal shell. Defaults to the magnifying glass. */
|
|
13
|
+
icon?: Component;
|
|
14
|
+
subtitle?: string;
|
|
15
|
+
searchPlaceholder?: string;
|
|
16
|
+
emptyMessage?: string;
|
|
17
|
+
noMatchMessage?: string;
|
|
18
|
+
/** Render the filter input and pill labels in the mono font (symbols, codes, ids). */
|
|
19
|
+
mono?: boolean;
|
|
20
|
+
maxWidthClass?: string;
|
|
21
|
+
closeText?: string;
|
|
22
|
+
/** aria-label of the group toggle. */
|
|
23
|
+
groupAriaLabel?: string;
|
|
24
|
+
allLabel?: string;
|
|
25
|
+
}
|
|
26
|
+
declare const __VLS_export: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
27
|
+
close: () => any;
|
|
28
|
+
pick: (item: PillPickerItem) => any;
|
|
29
|
+
}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
|
|
30
|
+
onClose?: (() => any) | undefined;
|
|
31
|
+
onPick?: ((item: PillPickerItem) => any) | undefined;
|
|
32
|
+
}>, {
|
|
33
|
+
maxWidthClass: string;
|
|
34
|
+
searchPlaceholder: string;
|
|
35
|
+
emptyMessage: string;
|
|
36
|
+
noMatchMessage: string;
|
|
37
|
+
mono: boolean;
|
|
38
|
+
closeText: string;
|
|
39
|
+
groupAriaLabel: string;
|
|
40
|
+
allLabel: string;
|
|
41
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
42
|
+
declare const _default: typeof __VLS_export;
|
|
43
|
+
export default _default;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
export interface UsePollingOptions {
|
|
3
|
+
/** Run `fn` immediately when polling starts (mount / resume). Default true. */
|
|
4
|
+
immediate?: boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Pause the interval while the tab is hidden and refresh + resume when it
|
|
7
|
+
* becomes visible again — a hidden tab has no reason to keep waking the
|
|
8
|
+
* backend. Default true.
|
|
9
|
+
*/
|
|
10
|
+
pauseWhenHidden?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Visibility-gated polling loop bound to the component lifecycle.
|
|
14
|
+
*
|
|
15
|
+
* Starts on mount, stops on unmount. With `pauseWhenHidden` (the default)
|
|
16
|
+
* the interval is torn down on `document.visibilitychange` → hidden and
|
|
17
|
+
* re-armed — with an immediate refresh — when the tab is shown again.
|
|
18
|
+
*
|
|
19
|
+
* Pass `intervalMs: null` for a refresh-only mode: `fn` runs on mount and
|
|
20
|
+
* on every return-to-visible, but no interval is scheduled. Useful for
|
|
21
|
+
* "reload this badge when the user comes back" data that doesn't warrant
|
|
22
|
+
* a timer.
|
|
23
|
+
*
|
|
24
|
+
* Rejections from an async `fn` are the caller's to handle — catch inside
|
|
25
|
+
* `fn`; the loop itself never swallows or reports them.
|
|
26
|
+
*/
|
|
27
|
+
export declare function usePolling(fn: () => void | Promise<void>, intervalMs: number | null, options?: UsePollingOptions): {
|
|
28
|
+
start: () => void;
|
|
29
|
+
stop: () => void;
|
|
30
|
+
active: Readonly<Ref<boolean>>;
|
|
31
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ComputedRef } from 'vue';
|
|
2
1
|
/**
|
|
3
2
|
* Centralized dark/light Tailwind class strings.
|
|
4
3
|
*
|
|
@@ -12,51 +11,55 @@ import { ComputedRef } from 'vue';
|
|
|
12
11
|
* <p :class="t.mutedText">...</p>
|
|
13
12
|
* </div>
|
|
14
13
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* The returned object is `reactive()`, so property access yields the
|
|
15
|
+
* plain class string while staying reactive to theme flips. (It used to
|
|
16
|
+
* be a plain object of ComputedRefs — Vue does NOT unwrap refs nested in
|
|
17
|
+
* plain objects inside template bindings, so `:class="t.card"` rendered
|
|
18
|
+
* the ref's own keys — `fn dep __v_isRef …` — instead of the classes.)
|
|
19
|
+
* Property access is string-valued now: do not append `.value`.
|
|
17
20
|
*/
|
|
18
21
|
export interface ThemeClasses {
|
|
19
22
|
/** Card surface: bg-gray-800 / bg-white, with border. */
|
|
20
|
-
card:
|
|
23
|
+
card: string;
|
|
21
24
|
/** Slightly darker card surface: bg-gray-900 / bg-white, with border. */
|
|
22
|
-
cardAlt:
|
|
25
|
+
cardAlt: string;
|
|
23
26
|
/** Page background. */
|
|
24
|
-
pageBg:
|
|
27
|
+
pageBg: string;
|
|
25
28
|
/** Standard border between cards/sections. */
|
|
26
|
-
border:
|
|
29
|
+
border: string;
|
|
27
30
|
/** Subtle divider (lighter than border). */
|
|
28
|
-
divider:
|
|
31
|
+
divider: string;
|
|
29
32
|
/** Page headings: white / gray-900. */
|
|
30
|
-
primaryText:
|
|
33
|
+
primaryText: string;
|
|
31
34
|
/** Softer headings: gray-100 / gray-800. */
|
|
32
|
-
primaryTextSoft:
|
|
35
|
+
primaryTextSoft: string;
|
|
33
36
|
/** Body copy on cards: gray-200 / gray-700. */
|
|
34
|
-
bodyText:
|
|
37
|
+
bodyText: string;
|
|
35
38
|
/** Form labels: gray-300 / gray-700. */
|
|
36
|
-
label:
|
|
39
|
+
label: string;
|
|
37
40
|
/** Secondary text: gray-400 / gray-600. */
|
|
38
|
-
mutedText:
|
|
41
|
+
mutedText: string;
|
|
39
42
|
/** Tertiary text: gray-500 / gray-600. */
|
|
40
|
-
subtleText:
|
|
43
|
+
subtleText: string;
|
|
41
44
|
/** Dimmest text: gray-500 in dark / gray-400 in light. */
|
|
42
|
-
dimText:
|
|
45
|
+
dimText: string;
|
|
43
46
|
/** Slightly more contrast than dimText: gray-400 / gray-500. */
|
|
44
|
-
dimTextAlt:
|
|
47
|
+
dimTextAlt: string;
|
|
45
48
|
/** Big illustration / empty-state icon: gray-600 / gray-300. */
|
|
46
|
-
illustration:
|
|
49
|
+
illustration: string;
|
|
47
50
|
/** Standard text input. */
|
|
48
|
-
input:
|
|
51
|
+
input: string;
|
|
49
52
|
/** Input + placeholder colour. */
|
|
50
|
-
inputWithPlaceholder:
|
|
53
|
+
inputWithPlaceholder: string;
|
|
51
54
|
/** Ghost / Cancel button. */
|
|
52
|
-
ghostButton:
|
|
55
|
+
ghostButton: string;
|
|
53
56
|
/** Emerald accent text: emerald-400 / emerald-600. */
|
|
54
|
-
emeraldText:
|
|
57
|
+
emeraldText: string;
|
|
55
58
|
/** Amber accent text: amber-400 / amber-600. */
|
|
56
|
-
amberText:
|
|
59
|
+
amberText: string;
|
|
57
60
|
/** Amber heading-weight: amber-300 / amber-700. */
|
|
58
|
-
amberTextStrong:
|
|
61
|
+
amberTextStrong: string;
|
|
59
62
|
/** Red accent text: red-400 / red-500. */
|
|
60
|
-
redText:
|
|
63
|
+
redText: string;
|
|
61
64
|
}
|
|
62
65
|
export declare function useThemeClasses(): ThemeClasses;
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export { default as BaseChipButton } from './components/BaseChipButton.vue';
|
|
|
32
32
|
export { default as BaseRemoveButton } from './components/BaseRemoveButton.vue';
|
|
33
33
|
export { default as BaseStatusPill } from './components/BaseStatusPill.vue';
|
|
34
34
|
export { default as BaseFileDropzone } from './components/BaseFileDropzone.vue';
|
|
35
|
+
export { default as BaseCodeBlock } from './components/BaseCodeBlock.vue';
|
|
35
36
|
export { default as BaseInput } from './components/BaseInput.vue';
|
|
36
37
|
export { default as BaseSelect } from './components/BaseSelect.vue';
|
|
37
38
|
export { default as BaseDropdown } from './components/BaseDropdown.vue';
|
|
@@ -41,6 +42,7 @@ export { default as BaseSpecFields } from './components/BaseSpecFields.vue';
|
|
|
41
42
|
export { default as BaseStatBreakdown } from './components/BaseStatBreakdown.vue';
|
|
42
43
|
export { default as BaseFilterChip } from './components/BaseFilterChip.vue';
|
|
43
44
|
export { default as BaseCredentialsForm } from './components/BaseCredentialsForm.vue';
|
|
45
|
+
export { default as BasePillPickerModal } from './components/BasePillPickerModal.vue';
|
|
44
46
|
export type { CredentialsView, CredentialsUpdate } from './components/BaseCredentialsForm.vue';
|
|
45
47
|
export { useTheme, initTheme } from './composables/useTheme';
|
|
46
48
|
export type { UseThemeOptions } from './composables/useTheme';
|
|
@@ -56,6 +58,8 @@ export { useNotifications } from './composables/useNotifications';
|
|
|
56
58
|
export { useQueryParamSync } from './composables/useQueryParamSync';
|
|
57
59
|
export { useFieldClasses } from './composables/useFieldClasses';
|
|
58
60
|
export type { FieldClasses } from './composables/useFieldClasses';
|
|
61
|
+
export { usePolling } from './composables/usePolling';
|
|
62
|
+
export type { UsePollingOptions } from './composables/usePolling';
|
|
59
63
|
export { AlertEnum } from './enums/AlertEnum';
|
|
60
64
|
export { BaseBadgeEnum } from './enums/BaseBadgeEnum';
|
|
61
65
|
export { BaseButtonEnum } from './enums/BaseButtonEnum';
|
|
@@ -76,12 +80,14 @@ export type { DropdownOption } from './types/dropdown';
|
|
|
76
80
|
export type { TableColumn } from './types/table';
|
|
77
81
|
export type { SpecField, SpecFieldType, SpecFieldValue } from './types/specField';
|
|
78
82
|
export type { StatBreakdownItem } from './types/statBreakdown';
|
|
83
|
+
export type { PillPickerItem } from './types/pillPicker';
|
|
79
84
|
export { getBaseColor, getBaseColorOf } from './utils/util';
|
|
80
85
|
export { methodBadgeSolid, methodBadgeBright, methodBadgeTinted, statusBadgeSolid, statusBadgeTinted, statusBadgeSoft, } from './utils/httpColors';
|
|
81
86
|
export { rowKeyMissing, rowValueMissing } from './utils/kvRows';
|
|
82
87
|
export type { KeyValueRowLike } from './utils/kvRows';
|
|
83
88
|
export { sanitizeHtml, isSafeHref } from './utils/sanitizeHtml';
|
|
84
|
-
export { fmtNumber, fmtDate, fmtDateTime, fmtDateTimeMs, fmtDateShort, fmtCalendarDate, fmtCalendarDateTime, fmtMsAsSeconds, fmtBytes, fmtPrice, fmtPct, fmtUsd, fmtDuration, } from './utils/format';
|
|
89
|
+
export { fmtNumber, fmtDate, fmtDateTime, fmtDateTimeMs, fmtDateShort, fmtCalendarDate, fmtCalendarDateTime, fmtMsAsSeconds, fmtBytes, fmtPrice, fmtPct, fmtUsd, fmtDuration, formatJson, stringifyValue, } from './utils/format';
|
|
90
|
+
export { isValidAbsoluteUrl, isValidJson, isValidXml, isValidBase64, } from './utils/validate';
|
|
85
91
|
export { buildSpecParams, firstInvalidNumericSpec } from './utils/specForm';
|
|
86
92
|
export { computePnL } from './utils/pnl';
|
|
87
93
|
export type { PnL, PnLInputs } from './utils/pnl';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One clickable pill in a BasePillPickerModal.
|
|
3
|
+
*
|
|
4
|
+
* `id` must be unique (it keys the pill and identifies the pick),
|
|
5
|
+
* `label` is what the pill shows and what the free-text filter matches,
|
|
6
|
+
* `group` assigns the pill to one of the modal's segmented-filter groups,
|
|
7
|
+
* `title` becomes the pill's tooltip.
|
|
8
|
+
*/
|
|
9
|
+
export interface PillPickerItem {
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
group?: string;
|
|
13
|
+
title?: string;
|
|
14
|
+
}
|