@salesforcedevs/dx-components 1.11.1 → 1.13.0-alpha

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dx-components",
3
- "version": "1.11.1",
3
+ "version": "1.13.0-alpha",
4
4
  "description": "DX Lightning web components",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -45,6 +45,5 @@
45
45
  },
46
46
  "volta": {
47
47
  "node": "18.18.0"
48
- },
49
- "gitHead": "c3d110ccf1b9da39d4ffe0aab2c8a05878333761"
48
+ }
50
49
  }
@@ -104,7 +104,11 @@ div.card-trial.recommended-border {
104
104
  var(--dx-g-card-border-radius);
105
105
  }
106
106
 
107
- .recommended-border .top-text {
107
+ .recommended-border .top-text:first-child {
108
+ margin-top: var(--dx-g-spacing-mlg);
109
+ }
110
+
111
+ .recommended-border .badge-container:first-child {
108
112
  margin-top: var(--dx-g-spacing-mlg);
109
113
  }
110
114
 
@@ -29,7 +29,13 @@
29
29
  <div class="recommended-container" if:true={recommended}>
30
30
  <span class="recommended-label">Recommended</span>
31
31
  </div>
32
- <div class={className} href={href} target={target} onclick={handleClick}>
32
+ <div
33
+ class={className}
34
+ href={href}
35
+ target={target}
36
+ onclick={handleClick}
37
+ lwc:if={isPrimary}
38
+ >
33
39
  <template if:true={topText}>
34
40
  <span class="top-text dx-text-body-4">{topText}</span>
35
41
  <dx-hr spacing="md"></dx-hr>
@@ -110,4 +116,92 @@
110
116
  </ul>
111
117
  <img if:true={imgSrc} src={imgSrc} alt="" />
112
118
  </div>
119
+ <div
120
+ id="secondary"
121
+ class={className}
122
+ href={href}
123
+ target={target}
124
+ onclick={handleClick}
125
+ lwc:if={isSecondary}
126
+ >
127
+ <div class="badge-container" lwc:if={badgeSymbol}>
128
+ <dx-icon-badge
129
+ class="badge-main"
130
+ background-color={badgeBackgroundColor}
131
+ symbol={badgeSymbol}
132
+ sprite={badgeSprite}
133
+ ></dx-icon-badge>
134
+ <dx-type-badge
135
+ if:true={typeBadgeValue}
136
+ value={typeBadgeValue}
137
+ color={typeBadgeColor}
138
+ size={typeBadgeSize}
139
+ dark={typeBadgeDark}
140
+ variant={typeBadgeVariant}
141
+ ></dx-type-badge>
142
+ </div>
143
+ <dx-card-title
144
+ href={href}
145
+ target={target}
146
+ header={header}
147
+ ></dx-card-title>
148
+ <span class="label dx-text-body-3">{label}</span>
149
+ <p class="body dx-text-body-2 static-font">{body}</p>
150
+ <span class="terms dx-text-body-3 static-font">{terms}</span>
151
+ <template if:true={topText}>
152
+ <dx-hr spacing="md"></dx-hr>
153
+ <p class="top-text dx-text-body-4">{topText}</p>
154
+ </template>
155
+ <ul class={detailsClassName} if:true={hasDetails}>
156
+ <template for:each={details} for:item="detail">
157
+ <li class="detail" key={detail}>
158
+ <dx-icon-badge
159
+ background-color={badgeBackgroundColor}
160
+ symbol="check"
161
+ ></dx-icon-badge>
162
+ <span class="detail-text dx-text-body-4">{detail}</span>
163
+ </li>
164
+ </template>
165
+ </ul>
166
+ <dx-hr lwc:if={hasButtons} spacing="lg"></dx-hr>
167
+ <dx-button
168
+ if:true={hasOneButton}
169
+ class="button-one"
170
+ size="large"
171
+ href={buttonOneHref}
172
+ variant="primary"
173
+ target={buttonOneTarget}
174
+ font="sans"
175
+ icon-symbol={buttonOneIcon}
176
+ icon-size={buttonOneIconSize}
177
+ >
178
+ {buttonOneCta}
179
+ </dx-button>
180
+ <div if:true={hasTwoButtons} class="button-container">
181
+ <dx-button
182
+ class="button-one"
183
+ size="large"
184
+ href={buttonOneHref}
185
+ variant="primary"
186
+ font="sans"
187
+ target={buttonOneTarget}
188
+ icon-symbol={buttonOneIcon}
189
+ icon-size={buttonOneIconSize}
190
+ >
191
+ {buttonOneCta}
192
+ </dx-button>
193
+ <dx-button
194
+ class="button-two"
195
+ size="large"
196
+ onclick={openModal}
197
+ variant="secondary"
198
+ font="sans"
199
+ icon-symbol={buttonTwoIcon}
200
+ icon-size={buttonTwoIconSize}
201
+ >
202
+ {buttonTwoCta}
203
+ </dx-button>
204
+ </div>
205
+ <img if:true={imgSrc} src={imgSrc} alt="" />
206
+ </div>
113
207
  </template>
@@ -2,6 +2,7 @@ import { LightningElement, api } from "lwc";
2
2
  import cx from "classnames";
3
3
  import { toJson } from "dxUtils/normalizers";
4
4
  import { track } from "dxUtils/analytics";
5
+ import { TrialCardVariant } from "typings/custom";
5
6
 
6
7
  export default class CardTrial extends LightningElement {
7
8
  @api badgeBackgroundColor?: string = "indigo-vibrant-90";
@@ -37,6 +38,7 @@ export default class CardTrial extends LightningElement {
37
38
  @api typeBadgeDark?: boolean = false;
38
39
  @api modalTypeBadgeValue?: string;
39
40
  @api modalTypeBadgeDark?: boolean;
41
+ @api variant: TrialCardVariant = "primary";
40
42
 
41
43
  @api
42
44
  get details() {
@@ -74,6 +76,14 @@ export default class CardTrial extends LightningElement {
74
76
  return this.isExternalURL(this.buttonOneHref) ? "_blank" : null;
75
77
  }
76
78
 
79
+ get isPrimary() {
80
+ return this.variant === "primary";
81
+ }
82
+
83
+ get isSecondary() {
84
+ return this.variant === "secondary";
85
+ }
86
+
77
87
  private _details!: string[];
78
88
  private _modalDetails!: [{ title: string; subtitle: string }];
79
89
  private _modalOpen = false;
@@ -14,6 +14,11 @@
14
14
  /* This class intentionally left blank. */
15
15
  }
16
16
 
17
+ .search-input {
18
+ margin-bottom: var(--dx-g-spacing-md);
19
+ width: 250px;
20
+ }
21
+
17
22
  @media (min-width: 640px) {
18
23
  .col-two,
19
24
  .col-three,
@@ -1,3 +1,18 @@
1
1
  <template>
2
+ <div class="search-input" lwc:if={isSearchable}>
3
+ <dx-input
4
+ class="search-box"
5
+ type="search"
6
+ placeholder={getSearchPlaceholder}
7
+ role="search"
8
+ aria-label="Search the below items"
9
+ icon-symbol="search"
10
+ size="small"
11
+ value={searchValue}
12
+ onchange={onInputChange}
13
+ shortcut-key="j"
14
+ clearable
15
+ ></dx-input>
16
+ </div>
2
17
  <div class={className}><slot onslotchange={onSlotChange}></slot></div>
3
18
  </template>
@@ -4,6 +4,11 @@ import { GridVariant, LightningSlotElement } from "typings/custom";
4
4
 
5
5
  const DEFAULT_COLUMNS = "three";
6
6
 
7
+ interface SlottedItem {
8
+ originalDiplayValue: string;
9
+ htmlElement: HTMLElement;
10
+ }
11
+
7
12
  export default class Grid extends LightningElement {
8
13
  @api
9
14
  get columns() {
@@ -16,8 +21,69 @@ export default class Grid extends LightningElement {
16
21
  this._columns = value;
17
22
  }
18
23
 
24
+ @api searchPlaceholder?: string;
25
+
26
+ /*
27
+ The data passed in must be an array of elements equal to the number of items
28
+ slotted into this grid. Each item in the array can either be a string, or an object.
29
+ In the second case, we will search on all the string values of these objects.
30
+ */
31
+ @api
32
+ set searchData(value: string) {
33
+ const data = JSON.parse(value);
34
+ this._searchData = data.map((item: any) =>
35
+ typeof item === "string"
36
+ ? item.toLowerCase()
37
+ : Object.values(item)
38
+ .filter((e) => typeof e === "string")
39
+ .join("")
40
+ .toLowerCase()
41
+ );
42
+ }
43
+ get searchData(): string[] {
44
+ return this._searchData;
45
+ }
46
+ searchValue: string = "";
47
+
48
+ private get isSearchable(): boolean {
49
+ return (
50
+ Boolean(this.searchData) &&
51
+ this._itemCount > 1 &&
52
+ this.searchData.length === this._itemCount
53
+ );
54
+ }
55
+
56
+ private get getSearchPlaceholder(): string {
57
+ return this.searchPlaceholder ? this.searchPlaceholder : "Search";
58
+ }
59
+
60
+ private onInputChange(e: CustomEvent) {
61
+ this.searchValue = e.detail.toLowerCase();
62
+ this.displaySearchResults();
63
+ }
64
+
65
+ private displaySearchResults() {
66
+ if (this.searchValue) {
67
+ this._slottedItems?.forEach((item, index) => {
68
+ const searchDatum = this._searchData[index];
69
+ if (searchDatum && searchDatum.indexOf(this.searchValue) > -1) {
70
+ item.htmlElement.style.display = item.originalDiplayValue;
71
+ } else {
72
+ item.htmlElement.style.display = "none";
73
+ }
74
+ });
75
+ } else {
76
+ // show all items
77
+ this._slottedItems?.forEach((item) => {
78
+ item.htmlElement.style.display = item.originalDiplayValue;
79
+ });
80
+ }
81
+ }
82
+
19
83
  _columns!: GridVariant;
20
- _itemCount: number | null = null;
84
+ _itemCount: number = 0;
85
+ _slottedItems?: SlottedItem[];
86
+ _searchData: string[] = [];
21
87
 
22
88
  private get className(): string {
23
89
  return cx("container", `col-${this.columns}`);
@@ -67,6 +133,16 @@ export default class Grid extends LightningElement {
67
133
  }
68
134
 
69
135
  onSlotChange(e: Event) {
70
- this._itemCount = (e.target as LightningSlotElement).assignedElements().length;
136
+ const slottedItems = (
137
+ e.target as LightningSlotElement
138
+ ).assignedElements();
139
+ this._itemCount = slottedItems.length;
140
+ this._slottedItems = slottedItems.map((item) => {
141
+ const htmlElement = item as HTMLElement;
142
+ return {
143
+ originalDiplayValue: htmlElement.style.display,
144
+ htmlElement: htmlElement
145
+ };
146
+ });
71
147
  }
72
148
  }
package/LICENSE DELETED
@@ -1,12 +0,0 @@
1
- Copyright (c) 2020, Salesforce.com, Inc.
2
- All rights reserved.
3
-
4
- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
-
6
- * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
-
8
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9
-
10
- * Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11
-
12
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.