@orangelogic/design-system 3.18.0 → 3.19.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/library/chunks/{asset-link-format.Bk1qHIQA.js → asset-link-format.ttcRQgDc.js} +5 -5
- package/library/chunks/{button.DCyoZrRj.js → button.D1YIxtv-.js} +1 -1
- package/library/chunks/{color-swatch-group.BtVbKp-v.js → color-swatch-group.Bumfw-G2.js} +4788 -4335
- package/library/chunks/{color-swatch.DxxOpJXT.js → color-swatch.DdsUysbF.js} +1 -1
- package/library/chunks/{confirm-popover.-_1n24v-.js → confirm-popover.CJXyEa5A.js} +3 -3
- package/library/chunks/{dialog.Dl9aHLD4.js → dialog.BbQ4Du0M.js} +2 -2
- package/library/chunks/{document-viewer.B-jtpLuD.js → document-viewer.C9tM2Gc7.js} +6 -6
- package/library/chunks/{dot-pagination.BNoG-qx7.js → dot-pagination.CJRAtM51.js} +1 -1
- package/library/chunks/{folder-select.DWaC4EWa.js → folder-select.BAPsI-gg.js} +4 -4
- package/library/chunks/gradient.CIzq8fOU.js +176 -0
- package/library/chunks/{header.v8maWlzT.js → header.BioJzPlg.js} +1 -1
- package/library/chunks/{i18n.CNnI4-0K.js → i18n.rtxrs1c1.js} +11 -3
- package/library/chunks/{icon-button.5-oAlIkv.js → icon-button.CbUddcgI.js} +1 -1
- package/library/chunks/{iframe.DOwG9Q7o.js → iframe.y7iCAVZP.js} +1 -1
- package/library/chunks/{image.BSh7WAGF.js → image.A2hE1WoV.js} +1 -1
- package/library/chunks/{index.Byin4Jfx.js → index.Coy2OPB4.js} +13 -13
- package/library/chunks/{input.Csf-S2nB.js → input.D1FFprPl.js} +1 -1
- package/library/chunks/{markdown.b03AOvFT.js → markdown.Dd_GFJK8.js} +2 -2
- package/library/chunks/{menu-item.HtTWOcq4.js → menu-item.0TbnDEDp.js} +1 -1
- package/library/chunks/{option.DgxoCq1j.js → option.CyorNG0S.js} +17 -17
- package/library/chunks/{pagination.C9NblxKt.js → pagination.D0BeaEIi.js} +5 -5
- package/library/chunks/{tab-group.B6Aej-jM.js → tab-group.C98CWzEH.js} +4 -4
- package/library/chunks/{tree.pId63hLe.js → tree.B7IKBX3n.js} +1 -1
- package/library/chunks/{types.Fkwo_sYp.js → types.DVZ_cbKn.js} +49 -48
- package/library/components/alert.js +2 -2
- package/library/components/asset-link-format.js +3 -3
- package/library/components/atoms.js +15 -15
- package/library/components/audio.js +2 -2
- package/library/components/border-input-group.js +2 -2
- package/library/components/breadcrumb.js +1 -1
- package/library/components/button.js +2 -2
- package/library/components/color-picker.js +971 -337
- package/library/components/color-swatch-group.js +3 -3
- package/library/components/color-swatch.js +2 -2
- package/library/components/confirm-popover.js +4 -4
- package/library/components/copy-button.js +1 -1
- package/library/components/corner-position-input-group.js +3 -3
- package/library/components/date-calendar.js +1 -1
- package/library/components/details.js +1 -1
- package/library/components/dialog.js +3 -3
- package/library/components/document-viewer.js +3 -3
- package/library/components/dot-pagination.js +2 -2
- package/library/components/drawer.js +2 -2
- package/library/components/dropdown.js +2 -2
- package/library/components/dynamic-select.js +4 -4
- package/library/components/e-chart.js +1 -1
- package/library/components/element-clamp.js +2 -2
- package/library/components/file-on-demand.js +9 -9
- package/library/components/folder-select.js +4 -4
- package/library/components/format-bytes.js +1 -1
- package/library/components/format-date.js +1 -1
- package/library/components/format-number.js +1 -1
- package/library/components/format-time.js +1 -1
- package/library/components/header.js +2 -2
- package/library/components/icon-button.js +2 -2
- package/library/components/iframe.js +2 -2
- package/library/components/image-comparer.js +1 -1
- package/library/components/image.js +2 -2
- package/library/components/input.js +2 -2
- package/library/components/line-clamp.js +1 -1
- package/library/components/markdown.js +3 -3
- package/library/components/masonry.js +2 -2
- package/library/components/menu-item.js +2 -2
- package/library/components/menu.js +2 -2
- package/library/components/molecules.js +3 -3
- package/library/components/option.js +2 -2
- package/library/components/organisms.js +2 -2
- package/library/components/padding-input-group.js +1 -1
- package/library/components/pagination.js +6 -6
- package/library/components/popup.js +1 -1
- package/library/components/position-picker.js +1 -1
- package/library/components/progress-bar.js +1 -1
- package/library/components/progress-ring.js +1 -1
- package/library/components/range.js +1 -1
- package/library/components/rating.js +1 -1
- package/library/components/relative-time.js +1 -1
- package/library/components/select.js +2 -2
- package/library/components/shadow-input-group.js +1 -1
- package/library/components/share-option-list.js +1 -1
- package/library/components/sidebar.js +1 -1
- package/library/components/size-input-group.js +3 -3
- package/library/components/spinner.js +1 -1
- package/library/components/split-panel.js +1 -1
- package/library/components/tab-group.js +5 -5
- package/library/components/tab.js +2 -2
- package/library/components/tag.js +2 -2
- package/library/components/tooltip.js +1 -1
- package/library/components/tree-item.js +2 -2
- package/library/components/tree.js +2 -2
- package/library/components/typeface.js +2 -2
- package/library/components/types.js +171 -161
- package/library/components/video.js +2 -2
- package/library/package.json +1 -1
- package/library/packages/atoms/src/components/color-picker/color-picker.d.ts +160 -2
- package/library/packages/atoms/src/components/color-picker/components/gradient-slider/gradient-slider.d.ts +80 -0
- package/library/packages/atoms/src/components/color-picker/components/gradient-slider/gradient-slider.styles.d.ts +2 -0
- package/library/packages/atoms/src/components/color-picker/components/gradient-stop-list/gradient-stop-list.d.ts +85 -0
- package/library/packages/atoms/src/components/color-picker/components/gradient-stop-list/gradient-stop-list.styles.d.ts +2 -0
- package/library/packages/atoms/src/components/input/input.d.ts +1 -1
- package/library/packages/atoms/src/components/option/option.d.ts +1 -1
- package/library/packages/events/src/cx-gradient-change.d.ts +10 -0
- package/library/packages/events/src/cx-gradient-stop-add.d.ts +9 -0
- package/library/packages/events/src/cx-gradient-stop-change.d.ts +10 -0
- package/library/packages/events/src/cx-gradient-stop-remove.d.ts +8 -0
- package/library/packages/events/src/cx-gradient-stop-select.d.ts +8 -0
- package/library/packages/events/src/cx-keydown.d.ts +4 -1
- package/library/packages/events/src/events.d.ts +5 -0
- package/library/packages/molecules/src/multi-select/components/board/board.d.ts +58 -2
- package/library/packages/molecules/src/multi-select/components/board-list-item/board-list-item.d.ts +14 -0
- package/library/packages/molecules/src/multi-select/controllers/filter-controller.d.ts +68 -0
- package/library/packages/molecules/src/multi-select/multi-select.d.ts +211 -0
- package/library/packages/molecules/src/multi-select/utils/base.d.ts +44 -0
- package/library/packages/molecules/src/multi-select/utils/reconcile.d.ts +57 -0
- package/library/packages/types/src/board.d.ts +25 -0
- package/library/packages/types/src/color-picker.d.ts +35 -2
- package/library/packages/utils/src/custom-element/i18n.d.ts +8 -0
- package/library/packages/utils/src/gradient/gradient.d.ts +65 -0
- package/library/packages/utils/src/gradient/index.d.ts +1 -0
- package/library/packages/utils/src/index.d.ts +1 -0
- package/library/react-web-component.d.ts +494 -470
- package/library/utils.js +143 -133
- package/package.json +1 -1
- package/library/packages/molecules/src/multi-select/multi-select.utils.d.ts +0 -3
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { BoardItem } from '../../../../types/src/board';
|
|
2
|
+
import { SelectedFacets } from '../../../../types/src/faceted-filter';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Where a filter came from.
|
|
6
|
+
*
|
|
7
|
+
* The `facet:` prefix is load-bearing rather than cosmetic: `facetCountingPool` tells facet
|
|
8
|
+
* sources apart from every other source by it, and that distinction *is* the drill-down rule.
|
|
9
|
+
* One source per facet field, mirroring how `cx-table`'s `FilterController` keys its own
|
|
10
|
+
* `dynamic:facet:<field>` sources.
|
|
11
|
+
*/
|
|
12
|
+
export type MultiSelectFilterSource = 'search' | `facet:${string}`;
|
|
13
|
+
/**
|
|
14
|
+
* The single owner of every filter `cx-multi-select` applies to its two boards.
|
|
15
|
+
*
|
|
16
|
+
* Each filter registers itself as a named source holding one predicate, and nothing outside this
|
|
17
|
+
* class decides how sources combine. Adding a filter is therefore one `set…` call in the handler
|
|
18
|
+
* that owns it: the AND below and the facet-counting pool both pick it up with no further edit.
|
|
19
|
+
* That is the failure this replaces — search used to narrow the boards without narrowing the pool
|
|
20
|
+
* the facet counts were tallied over, so the panel advertised counts no row could reach.
|
|
21
|
+
*
|
|
22
|
+
* Modelled on `packages/hybrid/table-core/src/table/controllers/filter-controller.ts`. That one
|
|
23
|
+
* hands filter descriptors to Tabulator, which does the filtering; there is no engine on this
|
|
24
|
+
* side, so sources hold predicates this class evaluates itself.
|
|
25
|
+
*/
|
|
26
|
+
export declare class MultiSelectFilterController {
|
|
27
|
+
private readonly sources;
|
|
28
|
+
get hasAnySource(): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Registers the toolbar search term, or drops the source when it is empty.
|
|
31
|
+
*
|
|
32
|
+
* Case-insensitive `includes` with no trimming — deliberately the same test `cx-board` applies
|
|
33
|
+
* to its own header search, so the two boxes select the same rows for the same text. They
|
|
34
|
+
* differ only in when they run: this one on Enter, the board's on every keystroke.
|
|
35
|
+
*/
|
|
36
|
+
setSearch(searchValue: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Reconciles one source per facet field from the whole selection map, the way
|
|
39
|
+
* `FilterController.syncFacetedFilters` does: fields that lost their last value are dropped,
|
|
40
|
+
* fields that have values are re-registered. Taking the entire map rather than one field at a
|
|
41
|
+
* time is what makes clearing a value as ordinary as adding one — there is no separate removal
|
|
42
|
+
* path to forget.
|
|
43
|
+
*
|
|
44
|
+
* AND across fields, since each field is its own source; OR within a field, via the set below.
|
|
45
|
+
*/
|
|
46
|
+
syncFacetSources(selectedFacets: SelectedFacets): void;
|
|
47
|
+
/**
|
|
48
|
+
* Rows passing every source, or `null` when nothing is filtering.
|
|
49
|
+
*
|
|
50
|
+
* `null` rather than "every row" lets the caller hand the board its full list untouched —
|
|
51
|
+
* same array, no filtering cost; an empty array means the opposite: no row may show.
|
|
52
|
+
* Result identity across calls is the caller's business (`stabilizeItems`), not this
|
|
53
|
+
* class's — two boards share this controller with two different pools, so a single cache
|
|
54
|
+
* here would thrash.
|
|
55
|
+
*/
|
|
56
|
+
filterItems(pool: BoardItem[]): BoardItem[] | null;
|
|
57
|
+
/**
|
|
58
|
+
* The pool a facet's values are counted over: every source applied *except* the facet ones.
|
|
59
|
+
*
|
|
60
|
+
* This is the whole drill-down policy, in one place. Leaving facet sources out is what keeps a
|
|
61
|
+
* value the user has not ticked yet reachable — counted against its siblings rather than
|
|
62
|
+
* against itself. The remaining facet-versus-facet part (a facet skips only its own constraint,
|
|
63
|
+
* never another facet's) belongs to `buildMetadataCounts`, which resolves it for every facet in
|
|
64
|
+
* a single pass.
|
|
65
|
+
*/
|
|
66
|
+
facetCountingPool(pool: BoardItem[]): BoardItem[];
|
|
67
|
+
private matchesEverySource;
|
|
68
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { default as CxIcon } from '../../../atoms/src/components/icon/icon.ts';
|
|
1
2
|
import { default as CxIconButton } from '../../../atoms/src/components/icon-button/icon-button.ts';
|
|
3
|
+
import { default as CxInput } from '../../../atoms/src/components/input/input.ts';
|
|
2
4
|
import { default as CxTooltip } from '../../../atoms/src/components/tooltip/tooltip.ts';
|
|
3
5
|
import { default as CortexElement } from '../../../base/src/cortex-element.ts';
|
|
6
|
+
import { default as CxFacetedFilter } from '../faceted-filter/faceted-filter.ts';
|
|
4
7
|
import { ColumnData } from '../../../types/src/multi-select';
|
|
5
8
|
import { PropertyValues, TemplateResult } from 'lit';
|
|
6
9
|
import { default as CxBoard } from './components/board/board';
|
|
@@ -9,17 +12,45 @@ import { default as CxBoard } from './components/board/board';
|
|
|
9
12
|
* @summary Multi-select allows the user to select multiple items from a list. The items can be moved between two columns. The user can move items between the columns by dragging and dropping them.
|
|
10
13
|
* @element cx-multi-select
|
|
11
14
|
*
|
|
15
|
+
* A toolbar above the two boards holds the filters. `canSearch` adds a search box there, applied
|
|
16
|
+
* on Enter, and giving items a `metadata` object adds a facet panel built from it, counted across
|
|
17
|
+
* both columns — `labelMap` then renames, reorders, or restricts those facets.
|
|
18
|
+
* Both narrow what the two boards display without changing the data they hold, so a selection
|
|
19
|
+
* made before filtering survives and still moves across with the arrow buttons — still-visible
|
|
20
|
+
* rows stay ticked, hidden ones are summarized on each board's header and footer.
|
|
21
|
+
*
|
|
22
|
+
* The filter panel opens whenever either is configured, since it also holds "Applied filters":
|
|
23
|
+
* the search term shows there as a removable chip, and the panel's "Clear" wipes the search along
|
|
24
|
+
* with any facets. With no `metadata` the panel simply has no facets to tick.
|
|
25
|
+
*
|
|
26
|
+
* Separately, `canSearchBoard` controls the search input each board renders in its own header.
|
|
27
|
+
* It defaults to the first board, matching how this component has always looked; set it to `''`
|
|
28
|
+
* and turn on `canSearch` to move that search up into the toolbar instead.
|
|
29
|
+
*
|
|
12
30
|
* @event {{ id: string; items: BoardItem[] }} cx-multi-select-change - Emitted when the list items change.
|
|
31
|
+
* @event {{ id: string }} cx-multi-select-configure - Emitted when the cog on a second-column row is activated. Requires `configurable`.
|
|
32
|
+
*
|
|
33
|
+
* @csspart board-1 - The first ("available") board.
|
|
34
|
+
* @csspart board-2 - The second ("selected") board.
|
|
35
|
+
* @csspart faceted-filter - The filter panel above the boards, holding the metadata facets and the applied-filter chips. Rendered whenever the toolbar is.
|
|
36
|
+
* @csspart search-input - The search box in the toolbar. Only rendered when `can-search` is set.
|
|
37
|
+
* @csspart search-input-clear - The clear button inside the search box, forwarded from `cx-input`'s
|
|
38
|
+
* own `clear-button` part. Only present while the box has text.
|
|
39
|
+
* @csspart tooltip - The tooltips wrapping the two move buttons.
|
|
40
|
+
*
|
|
41
|
+
* @cssproperty [--search-width=227px] - Width of the search box in the toolbar.
|
|
13
42
|
*
|
|
14
43
|
* @typedef BoardItem - {
|
|
15
44
|
* group: string;
|
|
16
45
|
* id: string;
|
|
17
46
|
* index?: string;
|
|
47
|
+
* metadata?: Record<string, string>;
|
|
18
48
|
* text: string;
|
|
19
49
|
* tooltip: string;
|
|
20
50
|
* }
|
|
21
51
|
*
|
|
22
52
|
* @typedef ColumnData - {
|
|
53
|
+
* dividerColor?: string;
|
|
23
54
|
* id: string;
|
|
24
55
|
* items: BoardItem[];
|
|
25
56
|
* sort?: boolean;
|
|
@@ -30,10 +61,19 @@ export default class CxMultiSelect extends CortexElement {
|
|
|
30
61
|
static readonly styles: import('lit').CSSResult[];
|
|
31
62
|
static readonly dependencies: {
|
|
32
63
|
'cx-board': typeof CxBoard;
|
|
64
|
+
'cx-faceted-filter': typeof CxFacetedFilter;
|
|
65
|
+
'cx-icon': typeof CxIcon;
|
|
33
66
|
'cx-icon-button': typeof CxIconButton;
|
|
67
|
+
'cx-input': typeof CxInput;
|
|
34
68
|
'cx-tooltip': typeof CxTooltip;
|
|
35
69
|
};
|
|
36
70
|
private readonly localize;
|
|
71
|
+
/**
|
|
72
|
+
* The single owner of the toolbar's filters. Both of them — the search box and the metadata
|
|
73
|
+
* facets — register themselves here as named sources, and it is this object, not any one
|
|
74
|
+
* handler, that decides how they combine. See `./filter-controller`.
|
|
75
|
+
*/
|
|
76
|
+
private readonly filters;
|
|
37
77
|
multiSelect: HTMLElement;
|
|
38
78
|
board1: CxBoard;
|
|
39
79
|
board2: CxBoard;
|
|
@@ -41,15 +81,100 @@ export default class CxMultiSelect extends CortexElement {
|
|
|
41
81
|
secondColumnData: ColumnData;
|
|
42
82
|
configurable: boolean;
|
|
43
83
|
ignoreTypes: string[];
|
|
84
|
+
/**
|
|
85
|
+
* Shows a search box in the toolbar that narrows both boards by item text. It applies on Enter
|
|
86
|
+
* (or when cleared), not while typing — unlike the input `cx-board` renders in its own header,
|
|
87
|
+
* which filters on every keystroke.
|
|
88
|
+
*
|
|
89
|
+
* Independent of `labelMap`: search works with no facets configured, and facets work with
|
|
90
|
+
* search turned off.
|
|
91
|
+
*/
|
|
92
|
+
canSearch: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Which boards render their own search input in their header, as a space-separated list of
|
|
95
|
+
* board positions — `'1'`, `'2'`, `'1 2'`, or `''` for neither. Space-separated to match how
|
|
96
|
+
* every other list-in-a-string attribute in the design system reads (`cx-dot-pagination`,
|
|
97
|
+
* `cx-menu`, `cx-popup`, …) and native HTML lists like `class` and `part`.
|
|
98
|
+
*
|
|
99
|
+
* Defaults to `'1'` because the first board has always shown that input; leaving it alone keeps
|
|
100
|
+
* every existing consumer looking exactly as it does today. Set it to `''` alongside
|
|
101
|
+
* `can-search` to move the search up into the toolbar, which is the point of having both:
|
|
102
|
+
* turning one on does not turn the other off, so a host that set both would show two search
|
|
103
|
+
* boxes filtering the same rows.
|
|
104
|
+
*
|
|
105
|
+
* A plain string rather than an array on purpose. The C# mirror serializes `string[]` as a JSON
|
|
106
|
+
* array while a delimiter-splitting Lit converter expects `'1 2'`, and the generator never sees
|
|
107
|
+
* the converter — the mismatch that leaves `cx-dot-pagination`'s `control-ids` unusable from the
|
|
108
|
+
* platform. A `string` goes down the same path as `href` or `label`, which does work.
|
|
109
|
+
*/
|
|
110
|
+
canSearchBoard: string;
|
|
111
|
+
/**
|
|
112
|
+
* Maps a `BoardItem.metadata` key to the facet group name shown in the filter panel. Doubles as
|
|
113
|
+
* the allowlist and the display order: naming three keys out of ten is how a host says the
|
|
114
|
+
* other seven are not filterable.
|
|
115
|
+
*
|
|
116
|
+
* Leaving it empty (the default) does not hide the filter — it falls back to every metadata key
|
|
117
|
+
* present, each headed by the raw key. So the panel appears as soon as items carry `metadata`,
|
|
118
|
+
* and `labelMap` is only needed to rename facets, reorder them, or leave some out. A host that
|
|
119
|
+
* wants no filter at all sends no `metadata`.
|
|
120
|
+
*/
|
|
121
|
+
labelMap: Record<string, string>;
|
|
44
122
|
addLimit: number | undefined;
|
|
45
123
|
private itemMap;
|
|
46
124
|
selectedItems: Record<string, string[]>;
|
|
47
125
|
private initialSecondColumnItems;
|
|
126
|
+
/** Facet config in `labelMap` order — bound to `cx-faceted-filter`'s `availableFacets`. */
|
|
127
|
+
private metadataFacetDetails;
|
|
128
|
+
/** Facet values with their drill-down counts — bound to `cx-faceted-filter`'s `facets`. */
|
|
129
|
+
private metadataFacets;
|
|
130
|
+
/** Values the user has ticked in the filter panel, keyed by metadata key. */
|
|
131
|
+
private selectedMetadataFacets;
|
|
132
|
+
/**
|
|
133
|
+
* The search term currently being applied — only what the user has committed with Enter or
|
|
134
|
+
* wiped with the clear button, never what is merely typed. The box itself holds the in-progress
|
|
135
|
+
* text, so there is no second field mirroring it here.
|
|
136
|
+
*/
|
|
137
|
+
searchValue: string;
|
|
48
138
|
private hasCapturedSecondColumnBaseline;
|
|
49
139
|
private board1Data;
|
|
50
140
|
private board2Data;
|
|
141
|
+
/**
|
|
142
|
+
* The original (unfiltered), sort-rule-applied list each board would show with no filter —
|
|
143
|
+
* NOT a snapshot of the consumer's initial data: it is re-derived in willUpdate() on every
|
|
144
|
+
* column-data change. Two jobs: the pool `recomputeBoardData` filters over, and a sort cache
|
|
145
|
+
* so the sort runs once per data change instead of on every filter recompute. With the
|
|
146
|
+
* default `sort` this is the very same reference as the column's `items`; only `sort: false`
|
|
147
|
+
* makes it a sorted copy.
|
|
148
|
+
*/
|
|
149
|
+
private board1OriginalData;
|
|
150
|
+
private board2OriginalData;
|
|
51
151
|
get firstColumnItemIds(): string[];
|
|
52
152
|
get secondColumnItemIds(): string[];
|
|
153
|
+
/**
|
|
154
|
+
* The facet key -> heading map actually in force.
|
|
155
|
+
*
|
|
156
|
+
* `labelMap` wins when the host supplies one, because it is an allowlist as well as a set of
|
|
157
|
+
* labels: naming three keys out of ten is how a host says the other seven are not filterable.
|
|
158
|
+
* With no `labelMap` there is nothing to allowlist against, so every metadata key present
|
|
159
|
+
* becomes a facet headed by the raw key — attaching `metadata` is then enough to get a filter.
|
|
160
|
+
*/
|
|
161
|
+
private get effectiveLabelMap();
|
|
162
|
+
/**
|
|
163
|
+
* Chips handed to `cx-faceted-filter` for filters it does not own itself — currently just the
|
|
164
|
+
* toolbar search term.
|
|
165
|
+
*
|
|
166
|
+
* This is what puts the search term under the panel's "Clear", and it is the only way to get it
|
|
167
|
+
* there: "Clear" reports itself by emitting `cx-faceted-filter-remove` once per chip supplied
|
|
168
|
+
* here, so with no chips it says nothing about the search at all. It also feeds the panel's
|
|
169
|
+
* applied-filter count, which is what decides whether the "Clear" button renders — without a
|
|
170
|
+
* chip, a search with no facet ticked leaves the count at zero and no button to press.
|
|
171
|
+
*
|
|
172
|
+
* Not gated on `canSearch`: if a term is somehow applied while the box is hidden it is still
|
|
173
|
+
* narrowing both boards, and a chip is then the only way to see and remove it.
|
|
174
|
+
*/
|
|
175
|
+
private get appliedFilterTags();
|
|
176
|
+
/** Board positions parsed out of `canSearchBoard`, tolerant of extra whitespace. */
|
|
177
|
+
private get boardsWithOwnSearch();
|
|
53
178
|
/**
|
|
54
179
|
* Validates the changes made to the items array based on the specified type of action ('add' or 'remove').
|
|
55
180
|
* If an add limit is set, it checks whether the new items exceed the allowed limit.
|
|
@@ -66,8 +191,94 @@ export default class CxMultiSelect extends CortexElement {
|
|
|
66
191
|
private handleMoveItems;
|
|
67
192
|
private handleMoveItemsRight;
|
|
68
193
|
private handleMoveItemsLeft;
|
|
194
|
+
/**
|
|
195
|
+
* Commits what is in the box on Enter — nothing filters until then. There is no separate draft
|
|
196
|
+
* field because `cx-input` is already holding the typed text: this only has to read it back at
|
|
197
|
+
* the moment the user commits. The `value` binding cannot fight that, since Lit re-commits an
|
|
198
|
+
* attribute binding only when the bound value changes, and `searchValue` changes only here.
|
|
199
|
+
*
|
|
200
|
+
* The parameter is typed with the payload `cx-input` actually emits (`{ event, value }`)
|
|
201
|
+
* rather than `CxKeydownEvent`, whose declared detail is empty — using the alias would type
|
|
202
|
+
* every detail read as `never`. Same situation as `cx-rich-text-toolbar`'s stepper handler,
|
|
203
|
+
* minus its cast.
|
|
204
|
+
*
|
|
205
|
+
* `preventDefault()` does double duty: `cx-input` schedules a form submit on an unmodified
|
|
206
|
+
* Enter and only skips it when the event was default-prevented, so without this an Enter here
|
|
207
|
+
* would submit whatever form the component sits in. The `isComposing` guard mirrors the one
|
|
208
|
+
* `cx-input` applies to that same submit — with an IME open, Enter is picking a candidate, not
|
|
209
|
+
* asking to search.
|
|
210
|
+
*/
|
|
211
|
+
private handleSearchKeydown;
|
|
212
|
+
/**
|
|
213
|
+
* Clears the applied term — the clear button is its own commit, so it does not wait for Enter.
|
|
214
|
+
* `cx-input` has already emptied itself and taken focus back by the time this runs.
|
|
215
|
+
*/
|
|
216
|
+
private handleSearchClear;
|
|
217
|
+
/**
|
|
218
|
+
* Removes one of the chips fed in through `appliedFilterTags`, either from its own X or from
|
|
219
|
+
* the panel's "Clear", which emits this once per chip before clearing its own facets.
|
|
220
|
+
*
|
|
221
|
+
* Assigning `searchValue` is the whole fix: the `@watch` below drops the search source from the
|
|
222
|
+
* controller, and the input's `value` binding empties the box. Unknown keys are ignored rather
|
|
223
|
+
* than thrown on — the panel may carry chips from filters added later.
|
|
224
|
+
*/
|
|
225
|
+
private handleAppliedFilterRemove;
|
|
226
|
+
private handleMetadataFacetChange;
|
|
227
|
+
/**
|
|
228
|
+
* Rebuilds the filter panel's own data — the facet config and the values with their counts.
|
|
229
|
+
*
|
|
230
|
+
* The pool is `itemMap` rather than the two `items` arrays concatenated: `itemMap` is keyed by
|
|
231
|
+
* id, so an item present in both columns collapses to one entry. Concatenating would count it
|
|
232
|
+
* twice for every item the deduplication above has not cut yet.
|
|
233
|
+
*
|
|
234
|
+
* `facetCountingPool` then applies every non-facet filter to it, so a count always predicts how
|
|
235
|
+
* many rows ticking that value would actually leave on screen. Which sources that covers is the
|
|
236
|
+
* controller's business, not this method's — that is the point of asking it rather than naming
|
|
237
|
+
* the search term here, as this once did and would have to keep doing for every filter added.
|
|
238
|
+
*
|
|
239
|
+
* A count can still reach zero for a value the user has already ticked; `buildMetadataCounts`
|
|
240
|
+
* keeps such values in the tally so they stay visible and removable.
|
|
241
|
+
*/
|
|
242
|
+
private rebuildMetadataFacets;
|
|
243
|
+
/**
|
|
244
|
+
* Pushes the controller's verdict into what the two boards receive. Only this derived,
|
|
245
|
+
* per-board view is filtered — the full column state (and with it `itemMap`, drag
|
|
246
|
+
* reporting, and the facet counting pool) always keeps every row the host owns.
|
|
247
|
+
*
|
|
248
|
+
* `stabilizeItems` hands back the previous array when nothing changed, because `cx-board`
|
|
249
|
+
* treats every new `data` reference as a real data change and resets its selection and
|
|
250
|
+
* scroll. An unrelated re-render must not do that.
|
|
251
|
+
*/
|
|
252
|
+
private recomputeBoardData;
|
|
253
|
+
/**
|
|
254
|
+
* Puts the visible part of the tracked selection back onto each board after a filter change.
|
|
255
|
+
*
|
|
256
|
+
* A filter change hands both boards a new `data` reference, and `cx-board` answers any data
|
|
257
|
+
* change by resetting its own selection — it cannot tell a filter from a real row change.
|
|
258
|
+
* This component can, so once the boards have processed the new data it restores what it
|
|
259
|
+
* still tracks. Ids the filter hides are not on the board to restore; they stay tracked
|
|
260
|
+
* here, which is what keeps the move buttons live and the display inputs truthful for them.
|
|
261
|
+
*/
|
|
262
|
+
private restoreBoardSelections;
|
|
263
|
+
/**
|
|
264
|
+
* No debouncing here, and none wanted: `searchValue` moves only when the user commits with
|
|
265
|
+
* Enter or clears the box, so this runs once per deliberate action rather than once per
|
|
266
|
+
* keystroke. The input holds the text in the meantime.
|
|
267
|
+
*/
|
|
268
|
+
onSearchValueChanged(): Promise<void>;
|
|
69
269
|
onSecondColumnDataChange(): void;
|
|
70
270
|
protected willUpdate(changedProperties: PropertyValues<this>): void;
|
|
271
|
+
/**
|
|
272
|
+
* The filter panel is rendered whenever the toolbar is, even with no facets to tick.
|
|
273
|
+
*
|
|
274
|
+
* Its facet list is only half of what it shows: the other half is "Applied filters", which holds
|
|
275
|
+
* the search chip and the "Clear" that removes it. Gating the whole panel on having facets took
|
|
276
|
+
* that away from anyone filtering by search alone — with no `metadata`, there was no panel, so
|
|
277
|
+
* no way to see or clear the term except the box's own X. `cx-faceted-filter` already renders
|
|
278
|
+
* its applied-filters header unconditionally and only its facet body on having facets, so an
|
|
279
|
+
* empty facet list costs nothing here.
|
|
280
|
+
*/
|
|
281
|
+
private renderFilterToolbar;
|
|
71
282
|
render(): TemplateResult;
|
|
72
283
|
}
|
|
73
284
|
declare global {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { BoardItem } from '../../../../types/src/board';
|
|
2
|
+
import { SelectedFacets } from '../../../../types/src/faceted-filter';
|
|
3
|
+
import { MetadataFacetData } from '../../../../types/src/multi-select';
|
|
4
|
+
|
|
5
|
+
export declare const compareFunction: (a: BoardItem, b: BoardItem) => number;
|
|
6
|
+
/**
|
|
7
|
+
* Counts items per `(facet key, value)` pair. The counting unit is the pair, never the value on
|
|
8
|
+
* its own — the same string under two different keys is two unrelated facet values.
|
|
9
|
+
*
|
|
10
|
+
* Counts drill down: a facet is tallied over the items satisfying every *other* selected facet,
|
|
11
|
+
* never its own. That is what keeps the values a user has not picked yet reachable instead of
|
|
12
|
+
* dropping them to zero the moment a sibling value is ticked.
|
|
13
|
+
*
|
|
14
|
+
* One pass over `items` is enough for that, because a facet counts an item exactly when the item
|
|
15
|
+
* fails no constraint other than the facet's own. So the item's number of failures decides
|
|
16
|
+
* everything: none means every facet counts it, exactly one means only the facet owning that
|
|
17
|
+
* failing constraint counts it, and two or more means no facet can — excluding one still leaves
|
|
18
|
+
* the other unsatisfied.
|
|
19
|
+
*
|
|
20
|
+
* Only keys present in `labelMap` become facets, so the host can push any metadata it likes and
|
|
21
|
+
* still control what is filterable. Facets that end up with no values are dropped rather than
|
|
22
|
+
* rendered empty.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildMetadataCounts(items: BoardItem[], labelMap: Record<string, string>, selectedFacets?: SelectedFacets): Map<string, Map<string, number>>;
|
|
25
|
+
/**
|
|
26
|
+
* Every metadata key present in `items`, mapped to itself — the fallback for a host that attaches
|
|
27
|
+
* metadata but does not say what to call each facet. Attaching metadata is then enough to get a
|
|
28
|
+
* filter, with the raw key as the group heading.
|
|
29
|
+
*
|
|
30
|
+
* Keys keep the order they are first seen in rather than being sorted, so the facet order follows
|
|
31
|
+
* the order the host wrote its own `metadata` objects in — the same thing `labelMap` controls when
|
|
32
|
+
* it is supplied. Re-assigning a key that is already present does not move it, so the plain
|
|
33
|
+
* assignment below is enough to keep that order.
|
|
34
|
+
*/
|
|
35
|
+
export declare function deriveLabelMapFromMetadata(items: BoardItem[]): Record<string, string>;
|
|
36
|
+
/**
|
|
37
|
+
* Maps raw counts onto the pair of bindings `cx-faceted-filter` expects.
|
|
38
|
+
*
|
|
39
|
+
* Both arrays are built from the same `labelMap` key order and share one `facetDetails` object
|
|
40
|
+
* per facet, because the component renders by iterating `availableFacets` and then looking the
|
|
41
|
+
* facet up in `facets` by `facetFieldName` — a mismatch between the two drops that facet
|
|
42
|
+
* silently.
|
|
43
|
+
*/
|
|
44
|
+
export declare function toMetadataFacetData(counts: Map<string, Map<string, number>>, labelMap: Record<string, string>): MetadataFacetData;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { BoardItem, HiddenSelectionState } from '../../../../types/src/board';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pure helpers that let `cx-multi-select` hand each `cx-board` a *filtered view* as plain
|
|
5
|
+
* `data` while its own column state keeps every row.
|
|
6
|
+
*
|
|
7
|
+
* The board is deliberately dumb: it only ever sees, and reports back, the rows it was given.
|
|
8
|
+
* With a filter active that report describes the visible list, not the column — so every
|
|
9
|
+
* board-reported change has to be merged back into the full list here, every board-relative
|
|
10
|
+
* index translated, and the selection the board cannot see summarized for its display-only
|
|
11
|
+
* inputs. With no filter active the visible list IS the full list and every function below
|
|
12
|
+
* degrades to the identity (or `None`), which keeps pre-filter behavior byte-identical.
|
|
13
|
+
*/
|
|
14
|
+
/** What `computeHiddenSelection` reports for one column. */
|
|
15
|
+
export interface HiddenSelectionSummary {
|
|
16
|
+
count: number;
|
|
17
|
+
state: HiddenSelectionState;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Returns `previous` when `next` holds exactly the same item objects in the same order, so an
|
|
21
|
+
* unchanged result keeps its array identity. Lit compares reactive properties by reference,
|
|
22
|
+
* and `cx-board` answers every new `data` reference by resetting its selection and scroll
|
|
23
|
+
* position — identity is what stops an unrelated re-render from doing that.
|
|
24
|
+
*/
|
|
25
|
+
export declare function stabilizeItems(next: BoardItem[], previous: BoardItem[]): BoardItem[];
|
|
26
|
+
/**
|
|
27
|
+
* Translates an insertion index expressed against the visible (filtered) list into an index in
|
|
28
|
+
* the full list, anchoring on the visible row the insertion lands before — hidden rows keep
|
|
29
|
+
* their position relative to their visible neighbors. Past the visible end, the insertion
|
|
30
|
+
* lands right after the last visible row (before any hidden tail), which is where the user
|
|
31
|
+
* saw it go; with nothing visible at all it appends at the absolute end.
|
|
32
|
+
*/
|
|
33
|
+
export declare function toFullInsertIndex(visibleIndex: number, visibleItems: BoardItem[], fullItems: BoardItem[]): number;
|
|
34
|
+
/**
|
|
35
|
+
* Merges a board-reported visible id list back into the full list the host owns.
|
|
36
|
+
*
|
|
37
|
+
* The report is treated as a delta against the visible list the host handed the board:
|
|
38
|
+
* visible rows missing from the report leave the full list, new ids are kept where the report
|
|
39
|
+
* puts them, and every hidden row stays attached to (in front of) the visible row that
|
|
40
|
+
* followed it — so hidden rows travel with their anchor on reorder and are never lost. A
|
|
41
|
+
* hidden group whose anchor itself left the board joins the tail: its position is
|
|
42
|
+
* unobservable while hidden, and the tail is the one placement that cannot collide with
|
|
43
|
+
* whatever the user just arranged.
|
|
44
|
+
*/
|
|
45
|
+
export declare function mergeVisibleListIntoFull(reportedIds: string[], visibleBefore: BoardItem[], fullItems: BoardItem[]): string[];
|
|
46
|
+
/**
|
|
47
|
+
* Describes the part of a column's tracked selection that the board cannot see, feeding the
|
|
48
|
+
* two display-only inputs `cx-board` renders (`hidden-selection`, `hidden-selected-count`).
|
|
49
|
+
*
|
|
50
|
+
* `All` mirrors what the header tick means when rows are visible — every selectable row of
|
|
51
|
+
* the whole column is selected — so "select all, then filter to nothing" keeps its tick and a
|
|
52
|
+
* partial selection keeps its dash. The board itself cannot make that call: it only holds the
|
|
53
|
+
* filtered rows, and the distinction needs the full column. The selectable exclusions mirror
|
|
54
|
+
* the board's own `selectableItems` (no synthetic group headers, no disabled rows, no ignored
|
|
55
|
+
* types).
|
|
56
|
+
*/
|
|
57
|
+
export declare function computeHiddenSelection(trackedSelectedIds: string[], visibleItems: BoardItem[], fullItems: BoardItem[], ignoreTypes: string[]): HiddenSelectionSummary;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Display-only summary of the selection a `cx-board` cannot see, supplied by the host that
|
|
3
|
+
* owns the selection (`cx-multi-select`). The board renders it (header tick/dash, footer
|
|
4
|
+
* count) and never acts on it.
|
|
5
|
+
*/
|
|
6
|
+
export declare enum HiddenSelectionState {
|
|
7
|
+
All = "all",
|
|
8
|
+
None = "none",
|
|
9
|
+
Partial = "partial"
|
|
10
|
+
}
|
|
11
|
+
export interface BoardItem {
|
|
12
|
+
/** When true, the item is locked: not draggable, not selectable, not movable. */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
group: string;
|
|
15
|
+
id: string;
|
|
16
|
+
index?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Free-form metadata supplied by the host. Each key is a facet field whose display name comes
|
|
19
|
+
* from `cx-multi-select`'s `labelMap`; keys absent from that map are ignored.
|
|
20
|
+
*/
|
|
21
|
+
metadata?: Record<string, string>;
|
|
22
|
+
text: string;
|
|
23
|
+
tooltip: string;
|
|
24
|
+
type?: string;
|
|
25
|
+
}
|
|
@@ -43,7 +43,40 @@ export type ParseColorValue = {
|
|
|
43
43
|
};
|
|
44
44
|
export declare enum ColorFormat {
|
|
45
45
|
Hex = "hex",
|
|
46
|
-
Rgb = "rgb",
|
|
47
46
|
Hsl = "hsl",
|
|
48
|
-
Hsv = "hsv"
|
|
47
|
+
Hsv = "hsv",
|
|
48
|
+
Rgb = "rgb"
|
|
49
49
|
}
|
|
50
|
+
/** The kind of CSS gradient produced by the color picker's gradient tab. */
|
|
51
|
+
export declare enum GradientType {
|
|
52
|
+
Linear = "linear",
|
|
53
|
+
Radial = "radial"
|
|
54
|
+
}
|
|
55
|
+
/** Which editing surface the color picker is currently on. */
|
|
56
|
+
export declare enum ColorPickerMode {
|
|
57
|
+
Gradient = "gradient",
|
|
58
|
+
Solid = "solid"
|
|
59
|
+
}
|
|
60
|
+
/** A single color stop within a gradient. */
|
|
61
|
+
export type GradientStop = {
|
|
62
|
+
/**
|
|
63
|
+
* The stop's color. Always stored in a format that carries alpha (`rgba()` or 8-digit hex)
|
|
64
|
+
* so round-tripping through the picker never silently drops opacity.
|
|
65
|
+
*/
|
|
66
|
+
color: string;
|
|
67
|
+
/**
|
|
68
|
+
* A stable identifier for the stop. Required because dragging a stop past another one
|
|
69
|
+
* re-sorts the array, and keyed rendering must not recreate the handle mid-drag.
|
|
70
|
+
*/
|
|
71
|
+
id: string;
|
|
72
|
+
/** Position along the gradient line, 0-100. */
|
|
73
|
+
position: number;
|
|
74
|
+
};
|
|
75
|
+
/** A parsed gradient: its type, angle, and stops. */
|
|
76
|
+
export type GradientValue = {
|
|
77
|
+
/** Angle in degrees, 0-360. Only meaningful when `type` is `GradientType.Linear`. */
|
|
78
|
+
angle: number;
|
|
79
|
+
/** Color stops, always sorted by `position` ascending, always at least two entries. */
|
|
80
|
+
stops: GradientStop[];
|
|
81
|
+
type: GradientType;
|
|
82
|
+
};
|
|
@@ -37,6 +37,7 @@ export interface Translation extends DefaultTranslation {
|
|
|
37
37
|
addControl: string;
|
|
38
38
|
addCurrent: string;
|
|
39
39
|
addFolderCard: string;
|
|
40
|
+
addGradientStop: string;
|
|
40
41
|
addLimitExceeded: (limit: number) => string;
|
|
41
42
|
addMarker: string;
|
|
42
43
|
addPageCard: string;
|
|
@@ -506,6 +507,10 @@ export interface Translation extends DefaultTranslation {
|
|
|
506
507
|
goToFirstPage: string;
|
|
507
508
|
goToLastPage: string;
|
|
508
509
|
goToSlide: (slide: number, count: number) => string;
|
|
510
|
+
gradient: string;
|
|
511
|
+
gradientAngle: string;
|
|
512
|
+
gradientStopNumber: (index: number) => string;
|
|
513
|
+
gradientStops: string;
|
|
509
514
|
grid: string;
|
|
510
515
|
groupBy: string;
|
|
511
516
|
guttersWidth: string;
|
|
@@ -516,6 +521,7 @@ export interface Translation extends DefaultTranslation {
|
|
|
516
521
|
height: string;
|
|
517
522
|
heightMode: string;
|
|
518
523
|
help: string;
|
|
524
|
+
hex: string;
|
|
519
525
|
hideCode: string;
|
|
520
526
|
hideColumn: string;
|
|
521
527
|
hidePassword: string;
|
|
@@ -810,6 +816,7 @@ export interface Translation extends DefaultTranslation {
|
|
|
810
816
|
quality: string;
|
|
811
817
|
qualityHelpText: string;
|
|
812
818
|
quote: string;
|
|
819
|
+
radial: string;
|
|
813
820
|
radixPoint: string;
|
|
814
821
|
read: string;
|
|
815
822
|
readingMode: string;
|
|
@@ -825,6 +832,7 @@ export interface Translation extends DefaultTranslation {
|
|
|
825
832
|
remove: string;
|
|
826
833
|
removeBlock: string;
|
|
827
834
|
removeFolder: (num: number) => string;
|
|
835
|
+
removeGradientStop: string;
|
|
828
836
|
renderAudio: string;
|
|
829
837
|
replace: string;
|
|
830
838
|
replaceAll: string;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { GradientStop, GradientValue } from '../../../types/src/color-picker';
|
|
2
|
+
|
|
3
|
+
/** A gradient needs at least a start and an end color to be meaningful. */
|
|
4
|
+
export declare const MIN_GRADIENT_STOPS = 2;
|
|
5
|
+
/**
|
|
6
|
+
* Creates a process-unique identifier for a gradient stop.
|
|
7
|
+
* @returns An identifier that stays stable for the lifetime of the stop.
|
|
8
|
+
* @example createStopId() => "gradient-stop-1"
|
|
9
|
+
*/
|
|
10
|
+
export declare function createStopId(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Splits a string on a separator, ignoring separators nested inside parentheses.
|
|
13
|
+
* Needed because `rgba(255, 0, 0, 1)` contains commas that must not split the stop list.
|
|
14
|
+
* @param value - The string to split.
|
|
15
|
+
* @param separator - The single character to split on.
|
|
16
|
+
* @returns The trimmed top-level segments, with empty segments removed.
|
|
17
|
+
* @example splitTopLevel('rgba(1, 2, 3, 1) 0%, #fff 100%', ',') => ['rgba(1, 2, 3, 1) 0%', '#fff 100%']
|
|
18
|
+
*/
|
|
19
|
+
export declare function splitTopLevel(value: string, separator: string): string[];
|
|
20
|
+
/**
|
|
21
|
+
* Normalizes any angle into the 0-360 range.
|
|
22
|
+
* @param degrees - The angle in degrees, possibly negative or above 360.
|
|
23
|
+
* @returns The equivalent angle within 0-360.
|
|
24
|
+
* @example normalizeAngle(-90) => 270
|
|
25
|
+
*/
|
|
26
|
+
export declare function normalizeAngle(degrees: number): number;
|
|
27
|
+
/**
|
|
28
|
+
* Sorts stops by position ascending, preserving the relative order of equal positions.
|
|
29
|
+
* @param stops - The stops to sort.
|
|
30
|
+
* @returns A new sorted array; the input is not mutated.
|
|
31
|
+
* @example sortStops([{ position: 100 }, { position: 0 }]) => [0%, 100%]
|
|
32
|
+
*/
|
|
33
|
+
export declare function sortStops(stops: GradientStop[]): GradientStop[];
|
|
34
|
+
/**
|
|
35
|
+
* Checks whether a value looks like a CSS gradient this module can handle.
|
|
36
|
+
* @param value - The candidate string.
|
|
37
|
+
* @returns True for `linear-gradient(...)` and `radial-gradient(...)` strings.
|
|
38
|
+
* @example isGradientString('linear-gradient(90deg, red, blue)') => true
|
|
39
|
+
*/
|
|
40
|
+
export declare function isGradientString(value: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Parses a CSS gradient string into structured stops.
|
|
43
|
+
* @param value - The gradient string to parse.
|
|
44
|
+
* @returns The parsed gradient, or null when the value is not a supported gradient or does
|
|
45
|
+
* not contain at least two valid color stops.
|
|
46
|
+
* @example parseGradient('linear-gradient(90deg, #f00 0%, #00f 100%)')
|
|
47
|
+
*/
|
|
48
|
+
export declare function parseGradient(value: string): GradientValue | null;
|
|
49
|
+
/**
|
|
50
|
+
* Serializes structured stops back into a CSS gradient string.
|
|
51
|
+
* @param value - The gradient to serialize.
|
|
52
|
+
* @returns A CSS gradient string suitable for a `background` declaration.
|
|
53
|
+
* @example serializeGradient({ angle: 90, stops, type: GradientType.Linear })
|
|
54
|
+
* => 'linear-gradient(90deg, #ff0000 0%, #0000ff 100%)'
|
|
55
|
+
*/
|
|
56
|
+
export declare function serializeGradient(value: GradientValue): string;
|
|
57
|
+
/**
|
|
58
|
+
* Computes the color a new stop should take when inserted at a position, by blending the
|
|
59
|
+
* two stops it falls between.
|
|
60
|
+
* @param stops - The existing stops; need not be sorted.
|
|
61
|
+
* @param position - Where the new stop is being inserted, 0-100.
|
|
62
|
+
* @returns An `rgba()` color string, or an empty string when there are no stops to blend.
|
|
63
|
+
* @example interpolateStopColor(redAtZeroAndBlueAtHundred, 50) => 'rgba(128, 0, 128, 1)'
|
|
64
|
+
*/
|
|
65
|
+
export declare function interpolateStopColor(stops: GradientStop[], position: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './gradient';
|