@salesforce/webapp-template-app-react-sample-b2x-experimental 1.116.12 → 1.117.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/dist/CHANGELOG.md +16 -0
- package/dist/force-app/main/default/webapplications/propertyrentalapp/package.json +3 -3
- package/dist/force-app/main/default/webapplications/propertyrentalapp/propertyrentalapp.webapplication-meta.xml +1 -0
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/features/object-search/components/FilterContext.tsx +44 -3
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/features/object-search/components/filters/NumericRangeFilter.tsx +48 -1
- package/dist/force-app/main/default/webapplications/propertyrentalapp/src/features/object-search/hooks/useObjectSearchParams.ts +86 -5
- package/dist/package-lock.json +2 -2
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.117.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.116.13...v1.117.0) (2026-03-27)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [1.116.13](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.116.12...v1.116.13) (2026-03-27)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
## [1.116.12](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.116.11...v1.116.12) (2026-03-27)
|
|
7
23
|
|
|
8
24
|
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"graphql:schema": "node scripts/get-graphql-schema.mjs"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@salesforce/sdk-data": "^1.
|
|
19
|
-
"@salesforce/webapp-experimental": "^1.
|
|
18
|
+
"@salesforce/sdk-data": "^1.117.0",
|
|
19
|
+
"@salesforce/webapp-experimental": "^1.117.0",
|
|
20
20
|
"@tailwindcss/vite": "^4.1.17",
|
|
21
21
|
"class-variance-authority": "^0.7.1",
|
|
22
22
|
"clsx": "^2.1.1",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"@graphql-eslint/eslint-plugin": "^4.1.0",
|
|
48
48
|
"@graphql-tools/utils": "^11.0.0",
|
|
49
49
|
"@playwright/test": "^1.49.0",
|
|
50
|
-
"@salesforce/vite-plugin-webapp-experimental": "^1.
|
|
50
|
+
"@salesforce/vite-plugin-webapp-experimental": "^1.117.0",
|
|
51
51
|
"@testing-library/jest-dom": "^6.6.3",
|
|
52
52
|
"@testing-library/react": "^16.1.0",
|
|
53
53
|
"@testing-library/user-event": "^14.5.2",
|
|
@@ -7,6 +7,9 @@ interface FilterContextValue {
|
|
|
7
7
|
onFilterChange: (field: string, value: ActiveFilterValue | undefined) => void;
|
|
8
8
|
onFilterRemove: (field: string) => void;
|
|
9
9
|
onReset: () => void;
|
|
10
|
+
onApply: () => void;
|
|
11
|
+
hasPendingChanges: boolean;
|
|
12
|
+
hasValidationError: boolean;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
const FilterContext = createContext<FilterContextValue | null>(null);
|
|
@@ -16,6 +19,9 @@ interface FilterProviderProps {
|
|
|
16
19
|
onFilterChange: (field: string, value: ActiveFilterValue | undefined) => void;
|
|
17
20
|
onFilterRemove: (field: string) => void;
|
|
18
21
|
onReset: () => void;
|
|
22
|
+
onApply?: () => void;
|
|
23
|
+
hasPendingChanges?: boolean;
|
|
24
|
+
hasValidationError?: boolean;
|
|
19
25
|
children: ReactNode;
|
|
20
26
|
}
|
|
21
27
|
|
|
@@ -24,10 +30,23 @@ export function FilterProvider({
|
|
|
24
30
|
onFilterChange,
|
|
25
31
|
onFilterRemove,
|
|
26
32
|
onReset,
|
|
33
|
+
onApply,
|
|
34
|
+
hasPendingChanges = false,
|
|
35
|
+
hasValidationError = false,
|
|
27
36
|
children,
|
|
28
37
|
}: FilterProviderProps) {
|
|
29
38
|
return (
|
|
30
|
-
<FilterContext.Provider
|
|
39
|
+
<FilterContext.Provider
|
|
40
|
+
value={{
|
|
41
|
+
filters,
|
|
42
|
+
onFilterChange,
|
|
43
|
+
onFilterRemove,
|
|
44
|
+
onReset,
|
|
45
|
+
onApply: onApply ?? (() => {}),
|
|
46
|
+
hasPendingChanges,
|
|
47
|
+
hasValidationError,
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
31
50
|
{children}
|
|
32
51
|
</FilterContext.Provider>
|
|
33
52
|
);
|
|
@@ -56,8 +75,14 @@ export function useFilterField(field: string) {
|
|
|
56
75
|
}
|
|
57
76
|
|
|
58
77
|
export function useFilterPanel() {
|
|
59
|
-
const { filters, onReset } = useFilterContext();
|
|
60
|
-
return {
|
|
78
|
+
const { filters, onReset, onApply, hasPendingChanges, hasValidationError } = useFilterContext();
|
|
79
|
+
return {
|
|
80
|
+
hasActiveFilters: filters.length > 0,
|
|
81
|
+
hasPendingChanges,
|
|
82
|
+
hasValidationError,
|
|
83
|
+
resetAll: onReset,
|
|
84
|
+
apply: onApply,
|
|
85
|
+
};
|
|
61
86
|
}
|
|
62
87
|
|
|
63
88
|
type FilterResetButtonProps = Omit<React.ComponentProps<typeof Button>, "onClick">;
|
|
@@ -71,3 +96,19 @@ export function FilterResetButton({ children, ...props }: FilterResetButtonProps
|
|
|
71
96
|
</Button>
|
|
72
97
|
);
|
|
73
98
|
}
|
|
99
|
+
|
|
100
|
+
type FilterApplyButtonProps = Omit<React.ComponentProps<typeof Button>, "onClick" | "disabled">;
|
|
101
|
+
|
|
102
|
+
export function FilterApplyButton({ children, ...props }: FilterApplyButtonProps) {
|
|
103
|
+
const { apply, hasPendingChanges, hasValidationError } = useFilterPanel();
|
|
104
|
+
return (
|
|
105
|
+
<Button
|
|
106
|
+
onClick={apply}
|
|
107
|
+
disabled={!hasPendingChanges || hasValidationError}
|
|
108
|
+
aria-label="Apply filters"
|
|
109
|
+
{...props}
|
|
110
|
+
>
|
|
111
|
+
{children ?? "Apply"}
|
|
112
|
+
</Button>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Input } from "../../../../components/ui/input";
|
|
2
2
|
import { Label } from "../../../../components/ui/label";
|
|
3
|
+
import { toast } from "sonner";
|
|
3
4
|
import { cn } from "../../../../lib/utils";
|
|
4
5
|
import { useFilterField } from "../FilterContext";
|
|
5
6
|
import type { ActiveFilterValue } from "../../utils/filterUtils";
|
|
@@ -8,6 +9,8 @@ interface NumericRangeFilterProps extends Omit<React.ComponentProps<"div">, "onC
|
|
|
8
9
|
field: string;
|
|
9
10
|
label: string;
|
|
10
11
|
helpText?: string;
|
|
12
|
+
minInputProps?: React.ComponentProps<typeof Input>;
|
|
13
|
+
maxInputProps?: React.ComponentProps<typeof Input>;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
export function NumericRangeFilter({
|
|
@@ -15,13 +18,22 @@ export function NumericRangeFilter({
|
|
|
15
18
|
label,
|
|
16
19
|
helpText,
|
|
17
20
|
className,
|
|
21
|
+
minInputProps,
|
|
22
|
+
maxInputProps,
|
|
18
23
|
...props
|
|
19
24
|
}: NumericRangeFilterProps) {
|
|
20
25
|
const { value, onChange } = useFilterField(field);
|
|
21
26
|
return (
|
|
22
27
|
<div className={cn("space-y-1.5", className)} {...props}>
|
|
23
28
|
<Label>{label}</Label>
|
|
24
|
-
<NumericRangeFilterInputs
|
|
29
|
+
<NumericRangeFilterInputs
|
|
30
|
+
field={field}
|
|
31
|
+
label={label}
|
|
32
|
+
value={value}
|
|
33
|
+
onChange={onChange}
|
|
34
|
+
minInputProps={minInputProps}
|
|
35
|
+
maxInputProps={maxInputProps}
|
|
36
|
+
/>
|
|
25
37
|
{helpText && <p className="text-xs text-muted-foreground">{helpText}</p>}
|
|
26
38
|
</div>
|
|
27
39
|
);
|
|
@@ -46,6 +58,24 @@ export function NumericRangeFilterInputs({
|
|
|
46
58
|
maxInputProps,
|
|
47
59
|
...props
|
|
48
60
|
}: NumericRangeFilterInputsProps) {
|
|
61
|
+
const validateNumericRangeFilter = (filter: ActiveFilterValue) => {
|
|
62
|
+
if (filter.type !== "numeric") return null;
|
|
63
|
+
|
|
64
|
+
const min = filter.min?.trim();
|
|
65
|
+
const max = filter.max?.trim();
|
|
66
|
+
const filterLabel = filter.label || filter.field;
|
|
67
|
+
|
|
68
|
+
if (!min || !max) return null;
|
|
69
|
+
|
|
70
|
+
const minValue = Number(min);
|
|
71
|
+
const maxValue = Number(max);
|
|
72
|
+
if (!Number.isNaN(minValue) && !Number.isNaN(maxValue) && minValue >= maxValue) {
|
|
73
|
+
return `${filterLabel}: minimum value must be less than maximum value.`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return null;
|
|
77
|
+
};
|
|
78
|
+
|
|
49
79
|
const handleChange = (bound: "min" | "max", v: string) => {
|
|
50
80
|
const next = {
|
|
51
81
|
field,
|
|
@@ -55,6 +85,7 @@ export function NumericRangeFilterInputs({
|
|
|
55
85
|
max: value?.max ?? "",
|
|
56
86
|
[bound]: v,
|
|
57
87
|
};
|
|
88
|
+
|
|
58
89
|
if (!next.min && !next.max) {
|
|
59
90
|
onChange(undefined);
|
|
60
91
|
} else {
|
|
@@ -62,6 +93,20 @@ export function NumericRangeFilterInputs({
|
|
|
62
93
|
}
|
|
63
94
|
};
|
|
64
95
|
|
|
96
|
+
const handleBlur = (bound: "min" | "max", currentValue: string) => {
|
|
97
|
+
const next = {
|
|
98
|
+
field,
|
|
99
|
+
label,
|
|
100
|
+
type: "numeric" as const,
|
|
101
|
+
min: bound === "min" ? currentValue : (value?.min ?? ""),
|
|
102
|
+
max: bound === "max" ? currentValue : (value?.max ?? ""),
|
|
103
|
+
};
|
|
104
|
+
const validationError = validateNumericRangeFilter(next);
|
|
105
|
+
if (validationError) {
|
|
106
|
+
toast.error("Invalid range filter", { description: validationError });
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
65
110
|
return (
|
|
66
111
|
<div className={cn("flex gap-2", className)} {...props}>
|
|
67
112
|
<Input
|
|
@@ -69,6 +114,7 @@ export function NumericRangeFilterInputs({
|
|
|
69
114
|
placeholder="Min"
|
|
70
115
|
value={value?.min ?? ""}
|
|
71
116
|
onChange={(e) => handleChange("min", e.target.value)}
|
|
117
|
+
onBlur={(e) => handleBlur("min", e.target.value)}
|
|
72
118
|
aria-label={`${label} minimum`}
|
|
73
119
|
{...minInputProps}
|
|
74
120
|
/>
|
|
@@ -77,6 +123,7 @@ export function NumericRangeFilterInputs({
|
|
|
77
123
|
placeholder="Max"
|
|
78
124
|
value={value?.max ?? ""}
|
|
79
125
|
onChange={(e) => handleChange("max", e.target.value)}
|
|
126
|
+
onBlur={(e) => handleBlur("max", e.target.value)}
|
|
80
127
|
aria-label={`${label} maximum`}
|
|
81
128
|
{...maxInputProps}
|
|
82
129
|
/>
|
|
@@ -20,6 +20,11 @@ export interface UseObjectSearchParamsReturn<TFilter, TOrderBy> {
|
|
|
20
20
|
set: (field: string, value: ActiveFilterValue | undefined) => void;
|
|
21
21
|
remove: (field: string) => void;
|
|
22
22
|
};
|
|
23
|
+
filterState: {
|
|
24
|
+
apply: () => void;
|
|
25
|
+
hasPendingChanges: boolean;
|
|
26
|
+
hasValidationError: boolean;
|
|
27
|
+
};
|
|
23
28
|
sort: {
|
|
24
29
|
current: SortState | null;
|
|
25
30
|
set: (sort: SortState | null) => void;
|
|
@@ -36,6 +41,40 @@ export interface UseObjectSearchParamsReturn<TFilter, TOrderBy> {
|
|
|
36
41
|
resetAll: () => void;
|
|
37
42
|
}
|
|
38
43
|
|
|
44
|
+
export interface UseObjectSearchParamsOptions {
|
|
45
|
+
filterSyncMode?: "immediate" | "manual";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function areFiltersEqual(left: ActiveFilterValue[], right: ActiveFilterValue[]) {
|
|
49
|
+
if (left.length !== right.length) return false;
|
|
50
|
+
const normalize = (filters: ActiveFilterValue[]) =>
|
|
51
|
+
[...filters]
|
|
52
|
+
.sort((a, b) => a.field.localeCompare(b.field))
|
|
53
|
+
.map((filter) => ({
|
|
54
|
+
field: filter.field,
|
|
55
|
+
type: filter.type,
|
|
56
|
+
value: filter.value ?? "",
|
|
57
|
+
min: filter.min ?? "",
|
|
58
|
+
max: filter.max ?? "",
|
|
59
|
+
}));
|
|
60
|
+
return JSON.stringify(normalize(left)) === JSON.stringify(normalize(right));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function hasFilterValidationError(filters: ActiveFilterValue[]) {
|
|
64
|
+
for (const filter of filters) {
|
|
65
|
+
if (filter.type !== "numeric") continue;
|
|
66
|
+
const min = filter.min?.trim();
|
|
67
|
+
const max = filter.max?.trim();
|
|
68
|
+
if (!min || !max) continue;
|
|
69
|
+
const minValue = Number(min);
|
|
70
|
+
const maxValue = Number(max);
|
|
71
|
+
if (!Number.isNaN(minValue) && !Number.isNaN(maxValue) && minValue >= maxValue) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
39
78
|
/**
|
|
40
79
|
* Manages filter, sort, and cursor-based pagination state for an object search page.
|
|
41
80
|
*
|
|
@@ -59,7 +98,11 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
59
98
|
filterConfigs: FilterFieldConfig[],
|
|
60
99
|
_sortConfigs?: SortFieldConfig[],
|
|
61
100
|
paginationConfig?: PaginationConfig,
|
|
101
|
+
options?: UseObjectSearchParamsOptions,
|
|
62
102
|
) {
|
|
103
|
+
const filterSyncMode = options?.filterSyncMode ?? "immediate";
|
|
104
|
+
const isManualFilterSync = filterSyncMode === "manual";
|
|
105
|
+
|
|
63
106
|
const defaultPageSize = paginationConfig?.defaultPageSize ?? 10;
|
|
64
107
|
const validPageSizes = useMemo(
|
|
65
108
|
() => paginationConfig?.validPageSizes ?? [defaultPageSize],
|
|
@@ -76,6 +119,7 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
76
119
|
);
|
|
77
120
|
|
|
78
121
|
const [filters, setFilters] = useState<ActiveFilterValue[]>(initial.filters);
|
|
122
|
+
const [appliedFilters, setAppliedFilters] = useState<ActiveFilterValue[]>(initial.filters);
|
|
79
123
|
const [sort, setLocalSort] = useState<SortState | null>(initial.sort);
|
|
80
124
|
|
|
81
125
|
// Pagination — cursor-based with a stack to support "previous page" navigation.
|
|
@@ -126,6 +170,15 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
126
170
|
|
|
127
171
|
const setFilter = useCallback(
|
|
128
172
|
(field: string, value: ActiveFilterValue | undefined) => {
|
|
173
|
+
if (isManualFilterSync) {
|
|
174
|
+
setFilters((prev) => {
|
|
175
|
+
const next = prev.filter((f) => f.field !== field);
|
|
176
|
+
if (value) next.push(value);
|
|
177
|
+
return next;
|
|
178
|
+
});
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
129
182
|
const { sort: s, pageSize: ps } = stateRef.current;
|
|
130
183
|
setFilters((prev) => {
|
|
131
184
|
const next = prev.filter((f) => f.field !== field);
|
|
@@ -135,11 +188,16 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
135
188
|
});
|
|
136
189
|
resetPagination();
|
|
137
190
|
},
|
|
138
|
-
[resetPagination],
|
|
191
|
+
[isManualFilterSync, resetPagination],
|
|
139
192
|
);
|
|
140
193
|
|
|
141
194
|
const removeFilter = useCallback(
|
|
142
195
|
(field: string) => {
|
|
196
|
+
if (isManualFilterSync) {
|
|
197
|
+
setFilters((prev) => prev.filter((f) => f.field !== field));
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
143
201
|
const { sort: s, pageSize: ps } = stateRef.current;
|
|
144
202
|
setFilters((prev) => {
|
|
145
203
|
const next = prev.filter((f) => f.field !== field);
|
|
@@ -148,9 +206,17 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
148
206
|
});
|
|
149
207
|
resetPagination();
|
|
150
208
|
},
|
|
151
|
-
[resetPagination],
|
|
209
|
+
[isManualFilterSync, resetPagination],
|
|
152
210
|
);
|
|
153
211
|
|
|
212
|
+
const applyFilters = useCallback(() => {
|
|
213
|
+
if (!isManualFilterSync) return;
|
|
214
|
+
const { filters: nextFilters, sort: s, pageSize: ps } = stateRef.current;
|
|
215
|
+
setAppliedFilters(nextFilters);
|
|
216
|
+
resetPagination();
|
|
217
|
+
syncToUrl(nextFilters, s, ps);
|
|
218
|
+
}, [isManualFilterSync, resetPagination, syncToUrl]);
|
|
219
|
+
|
|
154
220
|
// -- Sort callback ----------------------------------------------------------
|
|
155
221
|
|
|
156
222
|
const setSort = useCallback(
|
|
@@ -167,6 +233,7 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
167
233
|
|
|
168
234
|
const resetAll = useCallback(() => {
|
|
169
235
|
setFilters([]);
|
|
236
|
+
setAppliedFilters([]);
|
|
170
237
|
setLocalSort(null);
|
|
171
238
|
resetPagination();
|
|
172
239
|
syncToUrl([], null, defaultPageSize, 0);
|
|
@@ -216,8 +283,8 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
216
283
|
// Translate local filter/sort state into API-ready `where` and `orderBy`.
|
|
217
284
|
|
|
218
285
|
const where = useMemo(
|
|
219
|
-
() => buildFilter<TFilter>(filters, filterConfigs),
|
|
220
|
-
[filters, filterConfigs],
|
|
286
|
+
() => buildFilter<TFilter>(isManualFilterSync ? appliedFilters : filters, filterConfigs),
|
|
287
|
+
[appliedFilters, filters, filterConfigs, isManualFilterSync],
|
|
221
288
|
);
|
|
222
289
|
|
|
223
290
|
const orderBy = useMemo(() => buildOrderBy<TOrderBy>(sort), [sort]);
|
|
@@ -229,10 +296,23 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
229
296
|
// causing unnecessary re-renders.
|
|
230
297
|
|
|
231
298
|
const filtersGroup = useMemo(
|
|
232
|
-
() => ({
|
|
299
|
+
() => ({
|
|
300
|
+
active: filters,
|
|
301
|
+
set: setFilter,
|
|
302
|
+
remove: removeFilter,
|
|
303
|
+
}),
|
|
233
304
|
[filters, setFilter, removeFilter],
|
|
234
305
|
);
|
|
235
306
|
|
|
307
|
+
const filterState = useMemo(
|
|
308
|
+
() => ({
|
|
309
|
+
apply: applyFilters,
|
|
310
|
+
hasPendingChanges: isManualFilterSync ? !areFiltersEqual(filters, appliedFilters) : false,
|
|
311
|
+
hasValidationError: hasFilterValidationError(filters),
|
|
312
|
+
}),
|
|
313
|
+
[applyFilters, isManualFilterSync, filters, appliedFilters],
|
|
314
|
+
);
|
|
315
|
+
|
|
236
316
|
const sortGroup = useMemo(() => ({ current: sort, set: setSort }), [sort, setSort]);
|
|
237
317
|
|
|
238
318
|
const query = useMemo(() => ({ where, orderBy }), [where, orderBy]);
|
|
@@ -244,6 +324,7 @@ export function useObjectSearchParams<TFilter, TOrderBy>(
|
|
|
244
324
|
|
|
245
325
|
return {
|
|
246
326
|
filters: filtersGroup,
|
|
327
|
+
filterState,
|
|
247
328
|
sort: sortGroup,
|
|
248
329
|
query,
|
|
249
330
|
pagination,
|
package/dist/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/webapp-template-base-sfdx-project-experimental",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.117.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@salesforce/webapp-template-base-sfdx-project-experimental",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.117.0",
|
|
10
10
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"@lwc/eslint-plugin-lwc": "^3.3.0",
|
package/dist/package.json
CHANGED
package/package.json
CHANGED