@eturnity/eturnity_reusable_components 9.37.2 → 9.37.3-ATE-87.2
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 +40 -17
- package/dist/eturnity-consent-bridge.md +33 -15
- package/dist/index.es3.js +3 -3
- package/package.json +1 -1
- package/src/assets/svgIcons/_readme.md +2 -1
- package/src/assets/theme.js +3 -3
- package/src/components/filter/parentDropdown.vue +1 -0
- package/src/components/selectedOptions/index.vue +69 -100
- package/src/components/selectedOptions/selectedOptions.spec.js +243 -6
- package/src/components/selectedOptions/selectedOptions.stories.js +6 -5
- package/src/assets/svgIcons/meter.svg +0 -3
package/README.md
CHANGED
|
@@ -10,7 +10,8 @@ npm install @eturnity/eturnity_reusable_components
|
|
|
10
10
|
|
|
11
11
|
### Setting up the theme
|
|
12
12
|
|
|
13
|
-
The library now includes its own theme. You need to wrap your application with
|
|
13
|
+
The library now includes its own theme. You need to wrap your application with
|
|
14
|
+
the `ThemeProvider` component from this library.
|
|
14
15
|
|
|
15
16
|
**Recommended approach - Using the exported theme:**
|
|
16
17
|
|
|
@@ -66,7 +67,8 @@ import InputText from '@eturnity/eturnity_reusable_components/src/components/inp
|
|
|
66
67
|
|
|
67
68
|
### Overriding the theme (optional)
|
|
68
69
|
|
|
69
|
-
If you need to customize or override the theme, you can pass your own theme when
|
|
70
|
+
If you need to customize or override the theme, you can pass your own theme when
|
|
71
|
+
installing the plugin:
|
|
70
72
|
|
|
71
73
|
```javascript
|
|
72
74
|
import EturnityComponentsPlugin, {
|
|
@@ -124,22 +126,32 @@ Customers load provided files from jsDelivr using stable tag-based URLs:
|
|
|
124
126
|
<script src="https://cdn.jsdelivr.net/npm/@eturnity/eturnity_reusable_components@latest-consent-bridge/dist/eturnity-consent-bridge.min.js"></script>
|
|
125
127
|
```
|
|
126
128
|
|
|
127
|
-
Consent bridge integration documentation is maintained in
|
|
129
|
+
Consent bridge integration documentation is maintained in
|
|
130
|
+
`docs/eturnity-consent-bridge.md` and published to:
|
|
128
131
|
|
|
129
132
|
```text
|
|
130
133
|
https://cdn.jsdelivr.net/npm/@eturnity/eturnity_reusable_components@latest-consent-bridge/dist/eturnity-consent-bridge.md
|
|
131
134
|
```
|
|
132
135
|
|
|
133
|
-
Provided files and docs are configured in `provided-assets.config.js`. Script
|
|
136
|
+
Provided files and docs are configured in `provided-assets.config.js`. Script
|
|
137
|
+
and doc entries can both define their own `versionTag` (for example
|
|
138
|
+
`latest-consent-bridge`). Because customers keep these URLs unchanged, we update
|
|
139
|
+
what they receive by moving those npm dist-tags to a published package version.
|
|
134
140
|
|
|
135
141
|
### Build and publish behavior
|
|
136
142
|
|
|
137
|
-
- `npm run build` runs `vite build` (library), `npm run build:provided-files`
|
|
138
|
-
|
|
139
|
-
- `npm run
|
|
140
|
-
|
|
141
|
-
- `npm run
|
|
142
|
-
|
|
143
|
+
- `npm run build` runs `vite build` (library), `npm run build:provided-files`
|
|
144
|
+
(JS CDN bundles), and `npm run copy:provided-docs` (published docs).
|
|
145
|
+
- `npm run build:provided-files` builds files listed in
|
|
146
|
+
`provided-assets.config.js` into `dist/*.min.js`.
|
|
147
|
+
- `npm run copy:provided-docs` copies docs listed in `provided-assets.config.js`
|
|
148
|
+
into `dist/*.md`.
|
|
149
|
+
- `npm run verify:provided-files` checks expected provided files exist in
|
|
150
|
+
`dist/` and are non-empty.
|
|
151
|
+
- `npm run verify:provided-docs` checks expected provided docs exist in `dist/`
|
|
152
|
+
and are non-empty.
|
|
153
|
+
- `prepack` and `prepublishOnly` run both verification steps to reduce broken
|
|
154
|
+
publish risk.
|
|
143
155
|
|
|
144
156
|
### Standard release steps
|
|
145
157
|
|
|
@@ -149,9 +161,11 @@ Provided files and docs are configured in `provided-assets.config.js`. Script an
|
|
|
149
161
|
npm publish
|
|
150
162
|
```
|
|
151
163
|
|
|
152
|
-
2. Optional: promote provided-asset tag(s) so customer script/doc URLs point to
|
|
164
|
+
2. Optional: promote provided-asset tag(s) so customer script/doc URLs point to
|
|
165
|
+
that version.
|
|
153
166
|
|
|
154
|
-
Use this only if you want to update what customers receive from stable CDN tag
|
|
167
|
+
Use this only if you want to update what customers receive from stable CDN tag
|
|
168
|
+
URLs:
|
|
155
169
|
|
|
156
170
|
Script options (`--dry-run`, `--version=…`, `--name=…`, and combinations)
|
|
157
171
|
|
|
@@ -196,7 +210,8 @@ Optional tuning via environment variables:
|
|
|
196
210
|
|
|
197
211
|
### Optional rollback (re-point customer URL to older stable package)
|
|
198
212
|
|
|
199
|
-
If a promoted version is broken, you can optionally promote a previously
|
|
213
|
+
If a promoted version is broken, you can optionally promote a previously
|
|
214
|
+
published version:
|
|
200
215
|
|
|
201
216
|
```bash
|
|
202
217
|
npm run promote:provided-files-tag -- --version=<older-published-version>
|
|
@@ -217,11 +232,19 @@ npm run promote:provided-files-tag -- --version=9.15.2
|
|
|
217
232
|
|
|
218
233
|
Unit tests are Jest + `@vue/test-utils`, co-located with each component as
|
|
219
234
|
`componentName.spec.js`. Run a single spec with `pnpm test <path>` or the full
|
|
220
|
-
suite with `pnpm test`. See
|
|
221
|
-
for how we write tests
|
|
235
|
+
suite with `pnpm test`. See
|
|
236
|
+
[`docs/component-testing.md`](docs/component-testing.md) for how we write tests
|
|
237
|
+
(conventions, the TDD workflow, and using Claude Code).
|
|
222
238
|
|
|
223
239
|
## CI and pull requests
|
|
224
240
|
|
|
225
|
-
Opening or updating a pull request runs **Bitbucket Pipelines**
|
|
241
|
+
Opening or updating a pull request runs **Bitbucket Pipelines**
|
|
242
|
+
([`bitbucket-pipelines.yml`](bitbucket-pipelines.yml)): install with pnpm,
|
|
243
|
+
**`pnpm test`**, then **`pnpm run build`**. PRs are expected to pass this
|
|
244
|
+
pipeline.
|
|
226
245
|
|
|
227
|
-
**Blocking merges on failure** is configured in **Bitbucket repository
|
|
246
|
+
**Blocking merges on failure** is configured in **Bitbucket repository
|
|
247
|
+
settings** (not in this repo): enable merge checks that require a successful
|
|
248
|
+
pull-request build—for example a minimum number of successful builds for the PR,
|
|
249
|
+
or “require passing pipelines” if your plan supports it. Until that is enabled,
|
|
250
|
+
a red pipeline is visible but may not stop merges automatically.
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
# eturnityConsentBridge
|
|
2
2
|
|
|
3
|
-
Lightweight browser bridge for synchronizing consent-related cookie payloads
|
|
3
|
+
Lightweight browser bridge for synchronizing consent-related cookie payloads
|
|
4
|
+
between a host page and an embedded Eturnity iframe via `postMessage`.
|
|
4
5
|
|
|
5
6
|
## Overview
|
|
6
7
|
|
|
7
|
-
`eturnityConsentBridge` is a public browser/CDN script that exposes a global
|
|
8
|
+
`eturnityConsentBridge` is a public browser/CDN script that exposes a global
|
|
9
|
+
function:
|
|
8
10
|
|
|
9
11
|
- `window.eturnityConsentBridge(...)`
|
|
10
12
|
- `eturnityConsentBridge(...)`
|
|
11
13
|
|
|
12
|
-
It is designed for third-party embedding on customer websites and supports
|
|
14
|
+
It is designed for third-party embedding on customer websites and supports
|
|
15
|
+
multiple bridge instances (multiple iframes) on the same page.
|
|
13
16
|
|
|
14
17
|
## Features
|
|
15
18
|
|
|
16
19
|
- Global API for plain HTML and JavaScript-based script injection flows
|
|
17
|
-
- Safe message routing per iframe instance using `event.source` and origin
|
|
20
|
+
- Safe message routing per iframe instance using `event.source` and origin
|
|
21
|
+
checks
|
|
18
22
|
- Idempotent initialization for repeated calls with the same iframe ID
|
|
19
23
|
- Non-throwing input validation (returns `null` on invalid init input)
|
|
20
24
|
- Cookie fallback persistence and replay on iframe sync-ready handshake
|
|
@@ -57,7 +61,8 @@ Initialization returns:
|
|
|
57
61
|
- instance object on success
|
|
58
62
|
- `null` when validation fails
|
|
59
63
|
|
|
60
|
-
The iframe can be missing at init time; the bridge will keep trying to resolve
|
|
64
|
+
The iframe can be missing at init time; the bridge will keep trying to resolve
|
|
65
|
+
it during message handling.
|
|
61
66
|
|
|
62
67
|
## Message Contract
|
|
63
68
|
|
|
@@ -88,9 +93,12 @@ Stored cookie replay can be triggered in two safe ways:
|
|
|
88
93
|
- **on init**: right after bridge initialization (`eturnityConsentBridge(...)`)
|
|
89
94
|
- **on handshake**: when iframe sends `eturnity_<type>_cookie_sync_ready`
|
|
90
95
|
|
|
91
|
-
The init replay exists to avoid reload race conditions where the iframe
|
|
96
|
+
The init replay exists to avoid reload race conditions where the iframe
|
|
97
|
+
handshake might be sent before the host bridge is fully attached.
|
|
92
98
|
|
|
93
|
-
Delete events are also synchronized: when iframe sends
|
|
99
|
+
Delete events are also synchronized: when iframe sends
|
|
100
|
+
`eturnity_<type>_cookie_delete`, host removes that entry from its cache and then
|
|
101
|
+
emits `eturnity_<type>_cookie_sync` with `{ cookieName, isDeleted: true }`.
|
|
94
102
|
|
|
95
103
|
## API
|
|
96
104
|
|
|
@@ -116,7 +124,8 @@ Destroys one bridge instance.
|
|
|
116
124
|
|
|
117
125
|
### `eturnityConsentBridge.destroyAll()`
|
|
118
126
|
|
|
119
|
-
Destroys all bridge instances and removes the shared `message` listener when no
|
|
127
|
+
Destroys all bridge instances and removes the shared `message` listener when no
|
|
128
|
+
instances remain.
|
|
120
129
|
|
|
121
130
|
### `BridgeInstance.destroy()`
|
|
122
131
|
|
|
@@ -132,7 +141,8 @@ type BridgeOptions = {
|
|
|
132
141
|
```
|
|
133
142
|
|
|
134
143
|
- **`type`** (required): selects internal message/cookie namespace
|
|
135
|
-
- **`logs`** (optional, default `false`): enables verbose console logging for
|
|
144
|
+
- **`logs`** (optional, default `false`): enables verbose console logging for
|
|
145
|
+
this instance
|
|
136
146
|
|
|
137
147
|
Unknown option keys are ignored.
|
|
138
148
|
|
|
@@ -185,7 +195,8 @@ eturnityConsentBridge.destroyAll()
|
|
|
185
195
|
### `Iframe ... was not found during initialization`
|
|
186
196
|
|
|
187
197
|
- Verify iframe ID matches exactly.
|
|
188
|
-
- If iframe is rendered later, you can initialize early; bridge resolves context
|
|
198
|
+
- If iframe is rendered later, you can initialize early; bridge resolves context
|
|
199
|
+
again during runtime.
|
|
189
200
|
|
|
190
201
|
### `Could not resolve iframe origin`
|
|
191
202
|
|
|
@@ -193,15 +204,22 @@ eturnityConsentBridge.destroyAll()
|
|
|
193
204
|
|
|
194
205
|
### `Ignoring ... due to origin mismatch`
|
|
195
206
|
|
|
196
|
-
- Host and iframe messaging origins must match the iframe `src` origin resolved
|
|
207
|
+
- Host and iframe messaging origins must match the iframe `src` origin resolved
|
|
208
|
+
by the bridge.
|
|
197
209
|
|
|
198
210
|
### Why replay may happen before `cookie_sync_ready`
|
|
199
211
|
|
|
200
|
-
- This is expected behavior: replay on init is intentional and does not depend
|
|
201
|
-
|
|
202
|
-
-
|
|
212
|
+
- This is expected behavior: replay on init is intentional and does not depend
|
|
213
|
+
on handshake timing.
|
|
214
|
+
- In some page-load orders, the iframe can emit `cookie_sync_ready` before the
|
|
215
|
+
host bridge listener is attached; in that case you may not see a handshake
|
|
216
|
+
log.
|
|
217
|
+
- This does not break integration: the iframe consumes
|
|
218
|
+
`eturnity_<type>_cookie_sync` messages directly, and `cookie_sync_ready` is
|
|
219
|
+
only a replay signal from iframe to host.
|
|
203
220
|
|
|
204
221
|
### Cookie warning on non-HTTPS host
|
|
205
222
|
|
|
206
|
-
- The bridge writes cookies with `Secure`; on non-HTTPS pages browsers may
|
|
223
|
+
- The bridge writes cookies with `Secure`; on non-HTTPS pages browsers may
|
|
224
|
+
reject persistence.
|
|
207
225
|
- Use HTTPS in production embedding environments.
|
package/dist/index.es3.js
CHANGED
|
@@ -815,8 +815,8 @@ const theme = (() => {
|
|
|
815
815
|
iconBackgroundColor: semanticColors.buttonIcon.overlayWhite10
|
|
816
816
|
},
|
|
817
817
|
disabled: {
|
|
818
|
-
textColor: semanticColors.
|
|
819
|
-
backgroundColor:
|
|
818
|
+
textColor: semanticColors.transparentWhite[400],
|
|
819
|
+
backgroundColor: "transparent",
|
|
820
820
|
borderColor: "",
|
|
821
821
|
iconBackgroundColor: semanticColors.buttonIcon.none
|
|
822
822
|
}
|
|
@@ -843,7 +843,7 @@ const theme = (() => {
|
|
|
843
843
|
},
|
|
844
844
|
disabled: {
|
|
845
845
|
backgroundColor: "transparent",
|
|
846
|
-
textColor: semanticColors.
|
|
846
|
+
textColor: semanticColors.transparentWhite[400],
|
|
847
847
|
borderColor: "",
|
|
848
848
|
iconBackgroundColor: semanticColors.buttonIcon.none
|
|
849
849
|
}
|
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
colors in icons will be replaced in paths only.
|
|
4
4
|
|
|
5
|
-
if an svg contain a rect or polygon or circle you want color to be applied on,
|
|
5
|
+
if an svg contain a rect or polygon or circle you want color to be applied on,
|
|
6
|
+
convert them into path using:
|
|
6
7
|
|
|
7
8
|
https://thednp.github.io/svg-path-commander/convert.html
|
package/src/assets/theme.js
CHANGED
|
@@ -816,8 +816,8 @@ const theme = (() => {
|
|
|
816
816
|
iconBackgroundColor: semanticColors.buttonIcon.overlayWhite10,
|
|
817
817
|
},
|
|
818
818
|
disabled: {
|
|
819
|
-
textColor: semanticColors.
|
|
820
|
-
backgroundColor:
|
|
819
|
+
textColor: semanticColors.transparentWhite[400],
|
|
820
|
+
backgroundColor: 'transparent',
|
|
821
821
|
borderColor: '',
|
|
822
822
|
iconBackgroundColor: semanticColors.buttonIcon.none,
|
|
823
823
|
},
|
|
@@ -844,7 +844,7 @@ const theme = (() => {
|
|
|
844
844
|
},
|
|
845
845
|
disabled: {
|
|
846
846
|
backgroundColor: 'transparent',
|
|
847
|
-
textColor: semanticColors.
|
|
847
|
+
textColor: semanticColors.transparentWhite[400],
|
|
848
848
|
borderColor: '',
|
|
849
849
|
iconBackgroundColor: semanticColors.buttonIcon.none,
|
|
850
850
|
},
|
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
<TitleContainer>
|
|
6
6
|
<BoxTitle> {{ numberSelected }} {{ selectedText }} </BoxTitle>
|
|
7
7
|
<IconContainer @click="$emit('on-close')">
|
|
8
|
-
<Icon
|
|
8
|
+
<Icon
|
|
9
|
+
:color="theme.semanticColors.red[500]"
|
|
10
|
+
cursor="pointer"
|
|
11
|
+
name="close"
|
|
12
|
+
size="14px"
|
|
13
|
+
/>
|
|
9
14
|
</IconContainer>
|
|
10
15
|
</TitleContainer>
|
|
11
16
|
<DividerContainer>
|
|
@@ -15,17 +20,18 @@
|
|
|
15
20
|
<ExpandedListItem
|
|
16
21
|
v-for="item in expandedOptions"
|
|
17
22
|
:key="item.type"
|
|
23
|
+
data-test-id="expanded_option"
|
|
18
24
|
:disabled="item.disabled || false"
|
|
19
25
|
:has-component="!!item?.component"
|
|
20
|
-
:
|
|
26
|
+
:text-color="expandedItemColor(item)"
|
|
21
27
|
@click="
|
|
22
28
|
!item?.component && !item.disabled && $emit('on-' + item.type)
|
|
23
29
|
"
|
|
24
30
|
>
|
|
25
31
|
<ListItemWrapper
|
|
26
32
|
v-if="item?.component"
|
|
33
|
+
data-test-id="expanded_list_item"
|
|
27
34
|
:has-component="!!item?.component"
|
|
28
|
-
test-data-id="expanded_list_item"
|
|
29
35
|
@click="!item.disabled && toggleElement(item.type)"
|
|
30
36
|
>
|
|
31
37
|
<ListItemTitle>
|
|
@@ -38,7 +44,6 @@
|
|
|
38
44
|
<Icon
|
|
39
45
|
:color="theme.colors.white"
|
|
40
46
|
:cursor="item.disabled ? 'not-allowed' : 'pointer'"
|
|
41
|
-
:hovered-color="theme.colors.white"
|
|
42
47
|
name="arrow_right"
|
|
43
48
|
size="20px"
|
|
44
49
|
/>
|
|
@@ -60,42 +65,44 @@
|
|
|
60
65
|
<SelectedContainer>
|
|
61
66
|
{{ numberSelected }} {{ selectedText }}
|
|
62
67
|
</SelectedContainer>
|
|
63
|
-
<
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
<
|
|
68
|
+
<ActionsContainer>
|
|
69
|
+
<template v-if="optionsList.length">
|
|
70
|
+
<RCMainButton
|
|
71
|
+
v-for="item in limitedOptions"
|
|
72
|
+
:key="item.type"
|
|
73
|
+
app-theme="dark"
|
|
74
|
+
:data-id="item.dataId"
|
|
75
|
+
:is-disabled="item.disabled"
|
|
76
|
+
no-wrap
|
|
77
|
+
:text="item.name"
|
|
78
|
+
type="ghost"
|
|
79
|
+
:variant="item.variant"
|
|
80
|
+
@click="!item.disabled && $emit('on-' + item.type)"
|
|
81
|
+
/>
|
|
82
|
+
<IconContainer
|
|
83
|
+
v-if="optionsList.length > optionLimit || hasComponent"
|
|
84
|
+
data-test-id="more_actions_button_wrapper"
|
|
85
|
+
@click="expandOptions"
|
|
86
|
+
>
|
|
87
|
+
<ButtonContainer name="more_options,_tool_tips">
|
|
88
|
+
<DotItem />
|
|
89
|
+
<DotItem />
|
|
90
|
+
<DotItem />
|
|
91
|
+
</ButtonContainer>
|
|
92
|
+
</IconContainer>
|
|
93
|
+
</template>
|
|
94
|
+
<EmptyText v-else data-test-id="no_bulk_actions">
|
|
95
|
+
{{ noBulkActionsText }}
|
|
96
|
+
</EmptyText>
|
|
97
|
+
<IconContainer data-test-id="close_button" @click="$emit('on-close')">
|
|
90
98
|
<Icon
|
|
91
|
-
:color="theme.
|
|
99
|
+
:color="theme.semanticColors.red[500]"
|
|
92
100
|
cursor="pointer"
|
|
93
|
-
:hovered-color="theme.colors.white"
|
|
94
101
|
name="close"
|
|
95
102
|
size="14px"
|
|
96
103
|
/>
|
|
97
104
|
</IconContainer>
|
|
98
|
-
</
|
|
105
|
+
</ActionsContainer>
|
|
99
106
|
</BoxContainer>
|
|
100
107
|
</PageContainer>
|
|
101
108
|
</PageWrapper>
|
|
@@ -118,7 +125,8 @@
|
|
|
118
125
|
// {
|
|
119
126
|
// type: 'delete',
|
|
120
127
|
// name: 'Delete',
|
|
121
|
-
//
|
|
128
|
+
// variant: 'cancel', // default is 'main'
|
|
129
|
+
// dataId: 'button_bulk_delete'
|
|
122
130
|
// }
|
|
123
131
|
// ]
|
|
124
132
|
// @on-${type}="function" should $emit the callback for the 'type' in the optionsList
|
|
@@ -137,6 +145,7 @@
|
|
|
137
145
|
// </SelectedOptions>
|
|
138
146
|
import styled from 'vue3-styled-components'
|
|
139
147
|
import InfoText from '../infoText'
|
|
148
|
+
import RCMainButton from '../buttons/mainButton'
|
|
140
149
|
import Icon from '../icon'
|
|
141
150
|
import theme from '../../assets/theme'
|
|
142
151
|
|
|
@@ -149,7 +158,7 @@
|
|
|
149
158
|
`
|
|
150
159
|
|
|
151
160
|
const Divider = styled.div`
|
|
152
|
-
border-bottom: 1px solid
|
|
161
|
+
border-bottom: 1px solid ${(props) => props.theme.semanticColors.teal[600]};
|
|
153
162
|
width: 95%;
|
|
154
163
|
margin: 0 auto;
|
|
155
164
|
`
|
|
@@ -159,7 +168,6 @@
|
|
|
159
168
|
bottom: 30px;
|
|
160
169
|
left: 50%;
|
|
161
170
|
width: auto;
|
|
162
|
-
max-width: 70%;
|
|
163
171
|
transform: translateX(-50%);
|
|
164
172
|
z-index: 999;
|
|
165
173
|
`
|
|
@@ -170,13 +178,12 @@
|
|
|
170
178
|
left: 50%;
|
|
171
179
|
transform: translate(-50%, -50%);
|
|
172
180
|
border-radius: 4px;
|
|
173
|
-
background-color: rgba(0, 0, 0, 0.4);
|
|
174
181
|
`
|
|
175
182
|
|
|
176
183
|
const OptionsContainer = styled.div`
|
|
177
184
|
position: absolute;
|
|
178
185
|
left: 101%;
|
|
179
|
-
background-color: ${(props) => props.theme.colors.
|
|
186
|
+
background-color: ${(props) => props.theme.colors.transparentBlack2};
|
|
180
187
|
border-radius: 4px;
|
|
181
188
|
padding: 15px;
|
|
182
189
|
`
|
|
@@ -185,9 +192,9 @@
|
|
|
185
192
|
display: grid;
|
|
186
193
|
align-items: center;
|
|
187
194
|
height: 100%;
|
|
188
|
-
padding
|
|
195
|
+
padding: 0 24px;
|
|
189
196
|
white-space: nowrap;
|
|
190
|
-
border-right: 1px solid
|
|
197
|
+
border-right: 1px solid ${(props) => props.theme.semanticColors.teal[600]};
|
|
191
198
|
`
|
|
192
199
|
|
|
193
200
|
const TitleContainer = styled.div`
|
|
@@ -210,13 +217,11 @@
|
|
|
210
217
|
const BoxContainer = styled.div`
|
|
211
218
|
display: flex;
|
|
212
219
|
align-items: center;
|
|
213
|
-
background-color: ${(props) => props.theme.colors.
|
|
214
|
-
opacity: 90%;
|
|
220
|
+
background-color: ${(props) => props.theme.colors.transparentBlack2};
|
|
215
221
|
color: ${(props) => props.theme.colors.white};
|
|
216
222
|
border-radius: 4px;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
height: 45px;
|
|
223
|
+
font-size: 14px;
|
|
224
|
+
height: 62px;
|
|
220
225
|
`
|
|
221
226
|
|
|
222
227
|
const CenterBox = styled(BoxContainer)`
|
|
@@ -239,14 +244,10 @@
|
|
|
239
244
|
|
|
240
245
|
div {
|
|
241
246
|
// This is the dot color
|
|
242
|
-
background: ${(props) => props.theme.
|
|
247
|
+
background: ${(props) => props.theme.semanticColors.grey[600]};
|
|
243
248
|
}
|
|
244
249
|
`
|
|
245
250
|
|
|
246
|
-
const CloseContainer = styled.div`
|
|
247
|
-
margin-left: 20px;
|
|
248
|
-
`
|
|
249
|
-
|
|
250
251
|
const DotItem = styled.div`
|
|
251
252
|
width: 4px;
|
|
252
253
|
height: 4px;
|
|
@@ -254,38 +255,15 @@
|
|
|
254
255
|
border-radius: 50%;
|
|
255
256
|
`
|
|
256
257
|
|
|
257
|
-
const
|
|
258
|
+
const ActionsContainer = styled.div`
|
|
258
259
|
height: 100%;
|
|
259
260
|
display: flex;
|
|
260
261
|
align-items: center;
|
|
262
|
+
gap: 8px;
|
|
263
|
+
padding: 0 24px;
|
|
261
264
|
color: ${(props) => props.theme.colors.white};
|
|
262
265
|
`
|
|
263
266
|
|
|
264
|
-
const ListAttrs = {
|
|
265
|
-
disabled: Boolean,
|
|
266
|
-
hoverColor: String,
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
const ListItem = styled('div', ListAttrs)`
|
|
270
|
-
width: max-content;
|
|
271
|
-
height: 100%;
|
|
272
|
-
display: flex;
|
|
273
|
-
align-items: center;
|
|
274
|
-
padding: 0 10px;
|
|
275
|
-
cursor: ${(props) => (props.disabled ? 'not-allowed' : 'pointer')};
|
|
276
|
-
color: ${(props) => props.disabled && props.theme.colors.grey3};
|
|
277
|
-
|
|
278
|
-
&:hover {
|
|
279
|
-
background: rgba(255, 255, 255, 0.1);
|
|
280
|
-
color: ${(props) =>
|
|
281
|
-
props.disabled
|
|
282
|
-
? props.theme.colors.grey3
|
|
283
|
-
: props.hoverColor
|
|
284
|
-
? props.theme.colors[props.hoverColor]
|
|
285
|
-
: props.theme.colors.white};
|
|
286
|
-
}
|
|
287
|
-
`
|
|
288
|
-
|
|
289
267
|
const IconContainer = styled.div`
|
|
290
268
|
display: grid;
|
|
291
269
|
align-items: center;
|
|
@@ -293,10 +271,9 @@
|
|
|
293
271
|
height: 30px;
|
|
294
272
|
width: 30px;
|
|
295
273
|
cursor: pointer;
|
|
296
|
-
margin-left: 8px;
|
|
297
274
|
|
|
298
275
|
&:hover {
|
|
299
|
-
background:
|
|
276
|
+
background: ${(props) => props.theme.semanticColors.transparentTeal[400]};
|
|
300
277
|
border-radius: 4px;
|
|
301
278
|
}
|
|
302
279
|
`
|
|
@@ -309,8 +286,8 @@
|
|
|
309
286
|
|
|
310
287
|
const ExpandedListItem = styled('div', {
|
|
311
288
|
disabled: Boolean,
|
|
312
|
-
hoverColor: String,
|
|
313
289
|
hasComponent: Boolean,
|
|
290
|
+
textColor: String,
|
|
314
291
|
})`
|
|
315
292
|
width: 100%;
|
|
316
293
|
display: flex;
|
|
@@ -318,12 +295,10 @@
|
|
|
318
295
|
align-items: center;
|
|
319
296
|
padding: ${(props) => (props.hasComponent ? '0' : '13px 15px')};
|
|
320
297
|
cursor: ${(props) => (props.disabled ? 'not-allowed' : 'pointer')};
|
|
321
|
-
color: ${(props) => props.
|
|
298
|
+
color: ${(props) => props.textColor};
|
|
322
299
|
|
|
323
300
|
&:hover {
|
|
324
|
-
background:
|
|
325
|
-
color: ${(props) =>
|
|
326
|
-
props.disabled ? props.theme.colors.grey3 : props.theme.colors.white};
|
|
301
|
+
background: ${(props) => props.theme.semanticColors.transparentTeal[400]};
|
|
327
302
|
}
|
|
328
303
|
`
|
|
329
304
|
|
|
@@ -343,8 +318,7 @@
|
|
|
343
318
|
|
|
344
319
|
const EmptyText = styled.div`
|
|
345
320
|
color: ${(props) => props.theme.colors.white};
|
|
346
|
-
font-size:
|
|
347
|
-
padding-left: 16px;
|
|
321
|
+
font-size: 14px;
|
|
348
322
|
`
|
|
349
323
|
|
|
350
324
|
export default {
|
|
@@ -353,10 +327,10 @@
|
|
|
353
327
|
PageContainer,
|
|
354
328
|
BoxContainer,
|
|
355
329
|
SelectedContainer,
|
|
356
|
-
|
|
330
|
+
ActionsContainer,
|
|
357
331
|
ButtonContainer,
|
|
358
332
|
DotItem,
|
|
359
|
-
|
|
333
|
+
RCMainButton,
|
|
360
334
|
InfoText,
|
|
361
335
|
CenterBox,
|
|
362
336
|
Icon,
|
|
@@ -373,7 +347,6 @@
|
|
|
373
347
|
Divider,
|
|
374
348
|
DividerContainer,
|
|
375
349
|
ExpandedList,
|
|
376
|
-
CloseContainer,
|
|
377
350
|
},
|
|
378
351
|
props: {
|
|
379
352
|
optionsList: {
|
|
@@ -434,6 +407,13 @@
|
|
|
434
407
|
this.initializeOptions()
|
|
435
408
|
},
|
|
436
409
|
methods: {
|
|
410
|
+
expandedItemColor(item) {
|
|
411
|
+
const ghost = this.theme.mainButton.dark.ghost
|
|
412
|
+
const variant = ghost[item.variant] ?? ghost.main
|
|
413
|
+
const state = item.disabled ? 'disabled' : 'default'
|
|
414
|
+
|
|
415
|
+
return variant[state].textColor
|
|
416
|
+
},
|
|
437
417
|
initializeOptions() {
|
|
438
418
|
this.expandedOptions = [...this.optionsList]
|
|
439
419
|
.map((option, index) => {
|
|
@@ -457,17 +437,6 @@
|
|
|
457
437
|
this.expanded = !this.expanded
|
|
458
438
|
this.expandedOptions = this.optionsList
|
|
459
439
|
},
|
|
460
|
-
handleExpandedOptionClick(item) {
|
|
461
|
-
if (item.disabled) return
|
|
462
|
-
|
|
463
|
-
if (!item.component) {
|
|
464
|
-
this.$emit('on-' + item.type)
|
|
465
|
-
|
|
466
|
-
return
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
this.toggleElement(item.type)
|
|
470
|
-
},
|
|
471
440
|
},
|
|
472
441
|
}
|
|
473
442
|
</script>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
2
|
import { mount } from '@vue/test-utils'
|
|
3
3
|
import RCSelectedOptions from '@/components/selectedOptions'
|
|
4
|
+
import RCMainButton from '@/components/buttons/mainButton'
|
|
5
|
+
import RCIcon from '@/components/icon/Icon.vue'
|
|
4
6
|
import theme from '@/assets/theme'
|
|
5
7
|
|
|
6
8
|
jest.mock('@/components/icon/iconCache.mjs', () => ({
|
|
@@ -22,7 +24,7 @@ describe('RCSelectedOptions.vue', () => {
|
|
|
22
24
|
{
|
|
23
25
|
type: 'delete',
|
|
24
26
|
name: 'Delete',
|
|
25
|
-
|
|
27
|
+
variant: 'cancel',
|
|
26
28
|
},
|
|
27
29
|
],
|
|
28
30
|
}
|
|
@@ -58,7 +60,7 @@ describe('RCSelectedOptions.vue', () => {
|
|
|
58
60
|
expect(selectedOptions.exists()).toBe(true)
|
|
59
61
|
|
|
60
62
|
const noBulkActions = selectedOptions.find(
|
|
61
|
-
'[test-
|
|
63
|
+
'[data-test-id="no_bulk_actions"]'
|
|
62
64
|
)
|
|
63
65
|
expect(noBulkActions.exists()).toBe(true)
|
|
64
66
|
})
|
|
@@ -78,7 +80,7 @@ describe('RCSelectedOptions.vue', () => {
|
|
|
78
80
|
|
|
79
81
|
//since we have 2 options, and the limit is 4, we should not see "•••" button
|
|
80
82
|
const moreActionsButton = selectedOptions.find(
|
|
81
|
-
'[test-
|
|
83
|
+
'[data-test-id="more_actions_button_wrapper"]'
|
|
82
84
|
)
|
|
83
85
|
expect(moreActionsButton.exists()).toBe(false)
|
|
84
86
|
})
|
|
@@ -111,7 +113,7 @@ describe('RCSelectedOptions.vue', () => {
|
|
|
111
113
|
|
|
112
114
|
//since we a component parameter, we should see "•••" button
|
|
113
115
|
const moreActionsButton = selectedOptions.find(
|
|
114
|
-
'[test-
|
|
116
|
+
'[data-test-id="more_actions_button_wrapper"]'
|
|
115
117
|
)
|
|
116
118
|
expect(moreActionsButton.exists()).toBe(true)
|
|
117
119
|
})
|
|
@@ -146,7 +148,7 @@ describe('RCSelectedOptions.vue', () => {
|
|
|
146
148
|
|
|
147
149
|
//since we a component parameter, we should see "•••" button
|
|
148
150
|
const moreActionsButton = selectedOptions.find(
|
|
149
|
-
'[test-
|
|
151
|
+
'[data-test-id="more_actions_button_wrapper"]'
|
|
150
152
|
)
|
|
151
153
|
expect(moreActionsButton.exists()).toBe(true)
|
|
152
154
|
|
|
@@ -160,7 +162,7 @@ describe('RCSelectedOptions.vue', () => {
|
|
|
160
162
|
|
|
161
163
|
//toggle the element with the component parameter
|
|
162
164
|
const expandedListItems = selectedOptions.findAll(
|
|
163
|
-
'[test-
|
|
165
|
+
'[data-test-id="expanded_list_item"]'
|
|
164
166
|
)
|
|
165
167
|
|
|
166
168
|
//there should be only one since we have only one option with the component parameter
|
|
@@ -173,4 +175,239 @@ describe('RCSelectedOptions.vue', () => {
|
|
|
173
175
|
const setSupplierSlot = wrapper.find('[data-id="set_supplier"]')
|
|
174
176
|
expect(setSupplierSlot.exists()).toBe(true)
|
|
175
177
|
})
|
|
178
|
+
it('renders each collapsed option as a main button', async () => {
|
|
179
|
+
const wrapper = mount(RCSelectedOptions, {
|
|
180
|
+
props: simpleOptionsProps,
|
|
181
|
+
global: {
|
|
182
|
+
provide: {
|
|
183
|
+
theme,
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
await wrapper.vm.$nextTick()
|
|
189
|
+
|
|
190
|
+
const optionButtons = wrapper.findAllComponents(RCMainButton)
|
|
191
|
+
expect(optionButtons).toHaveLength(2)
|
|
192
|
+
expect(optionButtons[0].props('text')).toBe('Close')
|
|
193
|
+
expect(optionButtons[1].props('text')).toBe('Delete')
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('passes the option data id straight through to the button', async () => {
|
|
197
|
+
const wrapper = mount(RCSelectedOptions, {
|
|
198
|
+
props: {
|
|
199
|
+
...simpleOptionsProps,
|
|
200
|
+
optionsList: [
|
|
201
|
+
{ type: 'delete', name: 'Delete', dataId: 'button_bulk_delete' },
|
|
202
|
+
],
|
|
203
|
+
},
|
|
204
|
+
global: {
|
|
205
|
+
provide: {
|
|
206
|
+
theme,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
await wrapper.vm.$nextTick()
|
|
212
|
+
|
|
213
|
+
expect(wrapper.findComponent(RCMainButton).props('dataId')).toBe(
|
|
214
|
+
'button_bulk_delete'
|
|
215
|
+
)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('leaves the button without a data id when the option carries none', async () => {
|
|
219
|
+
const wrapper = mount(RCSelectedOptions, {
|
|
220
|
+
props: simpleOptionsProps,
|
|
221
|
+
global: {
|
|
222
|
+
provide: {
|
|
223
|
+
theme,
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
await wrapper.vm.$nextTick()
|
|
229
|
+
|
|
230
|
+
expect(wrapper.findComponent(RCMainButton).props('dataId')).toBe('')
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it('passes the option variant straight through to the button', async () => {
|
|
234
|
+
const wrapper = mount(RCSelectedOptions, {
|
|
235
|
+
props: simpleOptionsProps,
|
|
236
|
+
global: {
|
|
237
|
+
provide: {
|
|
238
|
+
theme,
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
await wrapper.vm.$nextTick()
|
|
244
|
+
|
|
245
|
+
const optionButtons = wrapper.findAllComponents(RCMainButton)
|
|
246
|
+
expect(optionButtons[0].props('variant')).toBe('main')
|
|
247
|
+
expect(optionButtons[1].props('variant')).toBe('cancel')
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
it('marks a disabled option as a disabled button and does not emit on click', async () => {
|
|
251
|
+
const wrapper = mount(RCSelectedOptions, {
|
|
252
|
+
props: {
|
|
253
|
+
...simpleOptionsProps,
|
|
254
|
+
optionsList: [
|
|
255
|
+
{
|
|
256
|
+
type: 'delete',
|
|
257
|
+
name: 'Delete',
|
|
258
|
+
disabled: true,
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
global: {
|
|
263
|
+
provide: {
|
|
264
|
+
theme,
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
await wrapper.vm.$nextTick()
|
|
270
|
+
|
|
271
|
+
const deleteButton = wrapper.findComponent(RCMainButton)
|
|
272
|
+
expect(deleteButton.props('isDisabled')).toBe(true)
|
|
273
|
+
|
|
274
|
+
await deleteButton.trigger('click')
|
|
275
|
+
expect(wrapper.emitted('on-delete')).toBeUndefined()
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
it('emits the option event when an enabled option is clicked', async () => {
|
|
279
|
+
const wrapper = mount(RCSelectedOptions, {
|
|
280
|
+
props: simpleOptionsProps,
|
|
281
|
+
global: {
|
|
282
|
+
provide: {
|
|
283
|
+
theme,
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
await wrapper.vm.$nextTick()
|
|
289
|
+
|
|
290
|
+
await wrapper.findAllComponents(RCMainButton)[1].trigger('click')
|
|
291
|
+
expect(wrapper.emitted('on-delete')).toHaveLength(1)
|
|
292
|
+
})
|
|
293
|
+
it('renders the close button and emits on-close even when there are no options', async () => {
|
|
294
|
+
const wrapper = mount(RCSelectedOptions, {
|
|
295
|
+
props: {
|
|
296
|
+
...simpleOptionsProps,
|
|
297
|
+
optionsList: [],
|
|
298
|
+
},
|
|
299
|
+
global: {
|
|
300
|
+
provide: {
|
|
301
|
+
theme,
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
await wrapper.vm.$nextTick()
|
|
307
|
+
|
|
308
|
+
const closeButton = wrapper.find('[data-test-id="close_button"]')
|
|
309
|
+
expect(closeButton.exists()).toBe(true)
|
|
310
|
+
|
|
311
|
+
await closeButton.trigger('click')
|
|
312
|
+
expect(wrapper.emitted('on-close')).toHaveLength(1)
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
const expandedItemColors = async (optionsList) => {
|
|
316
|
+
const wrapper = mount(RCSelectedOptions, {
|
|
317
|
+
props: {
|
|
318
|
+
...simpleOptionsProps,
|
|
319
|
+
optionsList,
|
|
320
|
+
},
|
|
321
|
+
global: {
|
|
322
|
+
provide: {
|
|
323
|
+
theme,
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
await wrapper
|
|
329
|
+
.find('[data-test-id="more_actions_button_wrapper"]')
|
|
330
|
+
.trigger('click')
|
|
331
|
+
await wrapper.vm.$nextTick()
|
|
332
|
+
|
|
333
|
+
return wrapper
|
|
334
|
+
.findAllComponents('[data-test-id="expanded_option"]')
|
|
335
|
+
.map((option) => option.props('textColor'))
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
it('styles a cancel option differently from the default options in the expanded list', async () => {
|
|
339
|
+
const [close, archive, remove] = await expandedItemColors([
|
|
340
|
+
{ type: 'close', name: 'Close' },
|
|
341
|
+
{ type: 'archive', name: 'Archive' },
|
|
342
|
+
{ type: 'delete', name: 'Delete', variant: 'cancel' },
|
|
343
|
+
{ type: 'supplier', name: 'Supplier', component: 'set_supplier' },
|
|
344
|
+
])
|
|
345
|
+
|
|
346
|
+
expect(archive).toBe(close)
|
|
347
|
+
expect(remove).not.toBe(close)
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
it('styles disabled options alike whatever the variant in the expanded list', async () => {
|
|
351
|
+
const [close, remove] = await expandedItemColors([
|
|
352
|
+
{ type: 'close', name: 'Close', disabled: true },
|
|
353
|
+
{ type: 'delete', name: 'Delete', variant: 'cancel', disabled: true },
|
|
354
|
+
{ type: 'supplier', name: 'Supplier', component: 'set_supplier' },
|
|
355
|
+
])
|
|
356
|
+
|
|
357
|
+
expect(remove).toBe(close)
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
it('takes expanded option colours from the ghost button theme', async () => {
|
|
361
|
+
const [close, remove, archive, purge] = await expandedItemColors([
|
|
362
|
+
{ type: 'close', name: 'Close' },
|
|
363
|
+
{ type: 'delete', name: 'Delete', variant: 'cancel' },
|
|
364
|
+
{ type: 'archive', name: 'Archive', disabled: true },
|
|
365
|
+
{ type: 'purge', name: 'Purge', variant: 'cancel', disabled: true },
|
|
366
|
+
{ type: 'supplier', name: 'Supplier', component: 'set_supplier' },
|
|
367
|
+
])
|
|
368
|
+
|
|
369
|
+
const ghost = theme.mainButton.dark.ghost
|
|
370
|
+
|
|
371
|
+
expect(close).toBe(ghost.main.default.textColor)
|
|
372
|
+
expect(remove).toBe(ghost.cancel.default.textColor)
|
|
373
|
+
expect(archive).toBe(ghost.main.disabled.textColor)
|
|
374
|
+
expect(purge).toBe(ghost.cancel.disabled.textColor)
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
it('uses the same close colour in the expanded modal as in the collapsed bar', async () => {
|
|
378
|
+
const wrapper = mount(RCSelectedOptions, {
|
|
379
|
+
props: {
|
|
380
|
+
...simpleOptionsProps,
|
|
381
|
+
optionsList: [
|
|
382
|
+
{ type: 'close', name: 'Close' },
|
|
383
|
+
{ type: 'supplier', name: 'Supplier', component: 'set_supplier' },
|
|
384
|
+
],
|
|
385
|
+
},
|
|
386
|
+
global: {
|
|
387
|
+
provide: {
|
|
388
|
+
theme,
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
await wrapper
|
|
394
|
+
.find('[data-test-id="more_actions_button_wrapper"]')
|
|
395
|
+
.trigger('click')
|
|
396
|
+
await wrapper.vm.$nextTick()
|
|
397
|
+
|
|
398
|
+
const closeIcon = wrapper
|
|
399
|
+
.findAllComponents(RCIcon)
|
|
400
|
+
.find((icon) => icon.props('name') === 'close')
|
|
401
|
+
|
|
402
|
+
expect(closeIcon.props('color')).toBe(theme.semanticColors.red[500])
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
it('falls back to the main variant when an option has an unknown variant', async () => {
|
|
406
|
+
const [mystery] = await expandedItemColors([
|
|
407
|
+
{ type: 'mystery', name: 'Mystery', variant: 'not_a_variant' },
|
|
408
|
+
{ type: 'supplier', name: 'Supplier', component: 'set_supplier' },
|
|
409
|
+
])
|
|
410
|
+
|
|
411
|
+
expect(mystery).toBe(theme.mainButton.dark.ghost.main.default.textColor)
|
|
412
|
+
})
|
|
176
413
|
})
|
|
@@ -9,7 +9,7 @@ export default {
|
|
|
9
9
|
optionsList: {
|
|
10
10
|
control: 'object',
|
|
11
11
|
description:
|
|
12
|
-
'Array of options to display. Each option should have a type and name, and can optionally have a component, disabled state,
|
|
12
|
+
'Array of options to display. Each option should have a type and name, and can optionally have a component, disabled state, variant, dataId, and disabledInfo.',
|
|
13
13
|
},
|
|
14
14
|
numberSelected: {
|
|
15
15
|
control: 'number',
|
|
@@ -49,7 +49,7 @@ Default.args = {
|
|
|
49
49
|
{
|
|
50
50
|
type: 'delete',
|
|
51
51
|
name: 'Delete',
|
|
52
|
-
|
|
52
|
+
variant: 'cancel',
|
|
53
53
|
},
|
|
54
54
|
],
|
|
55
55
|
numberSelected: 5,
|
|
@@ -98,7 +98,7 @@ ManyOptions.args = {
|
|
|
98
98
|
{
|
|
99
99
|
type: 'delete',
|
|
100
100
|
name: 'Delete',
|
|
101
|
-
|
|
101
|
+
variant: 'cancel',
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
104
|
type: 'archive',
|
|
@@ -132,7 +132,7 @@ CustomLabels.args = {
|
|
|
132
132
|
{
|
|
133
133
|
type: 'delete',
|
|
134
134
|
name: 'Delete',
|
|
135
|
-
|
|
135
|
+
variant: 'cancel',
|
|
136
136
|
},
|
|
137
137
|
],
|
|
138
138
|
numberSelected: 1,
|
|
@@ -158,7 +158,8 @@ CustomLabels.args = {
|
|
|
158
158
|
// {
|
|
159
159
|
// type: 'delete',
|
|
160
160
|
// name: 'Delete',
|
|
161
|
-
//
|
|
161
|
+
// variant: 'cancel', // default is 'main'
|
|
162
|
+
// dataId: 'button_bulk_delete'
|
|
162
163
|
// }
|
|
163
164
|
// ]
|
|
164
165
|
//
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
-
<path d="M7.99988 2C9.38419 2 10.7375 2.41068 11.8885 3.17969C13.0397 3.94883 13.9369 5.04227 14.4667 6.32129C14.9964 7.60027 15.1351 9.00747 14.8651 10.3652C14.6292 11.551 14.0911 12.6534 13.3065 13.5654L13.2294 13.6367C13.0359 13.7809 12.7574 13.7575 12.578 13.5781C12.3736 13.3731 12.3756 13.0424 12.5614 12.8203C13.1208 12.1523 13.5272 11.3687 13.7509 10.5254L13.8358 10.1611C14.0654 9.00695 13.9473 7.80988 13.4969 6.72266C13.0747 5.70353 12.3778 4.82341 11.4862 4.17871L11.3055 4.05273C10.3271 3.399 9.17662 3.0498 7.99988 3.0498C6.82316 3.04985 5.67263 3.39898 4.69421 4.05273C3.71591 4.70646 2.95314 5.63563 2.50281 6.72266L2.42273 6.92773C2.03943 7.95934 1.94869 9.07895 2.16394 10.1611C2.3593 11.143 2.79919 12.0571 3.43835 12.8203C3.62426 13.0425 3.62633 13.3731 3.42175 13.5781L3.33875 13.6455C3.16397 13.7608 2.93614 13.7604 2.77039 13.6367L2.69324 13.5654C2.00668 12.7673 1.50892 11.8234 1.23718 10.8057L1.13464 10.3652C0.881519 9.09233 0.987587 7.77593 1.43835 6.5625L1.53308 6.32129C2.02976 5.12224 2.84939 4.08667 3.89832 3.32812L4.11121 3.17969C5.26224 2.41066 6.61558 2.00004 7.99988 2ZM10.1093 5.1875C10.2817 4.97192 10.5968 4.93699 10.8124 5.10938C11.028 5.28188 11.063 5.59687 10.8905 5.8125L9.12781 8.01465C9.35847 8.27842 9.49988 8.62208 9.49988 9C9.49988 9.82843 8.82831 10.5 7.99988 10.5C7.17154 10.4999 6.49988 9.82836 6.49988 9C6.49988 8.17164 7.17154 7.50011 7.99988 7.5C8.08232 7.5 8.16324 7.50771 8.24207 7.52051L10.1093 5.1875ZM7.99988 8.5C7.72383 8.50011 7.49988 8.72392 7.49988 9C7.49988 9.27608 7.72383 9.49989 7.99988 9.5C8.27602 9.5 8.49988 9.27614 8.49988 9C8.49988 8.72386 8.27602 8.5 7.99988 8.5Z" fill="#263238"/>
|
|
3
|
-
</svg>
|