@spscommerce/ds-react 8.53.15 → 8.53.17

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/lib/index.js CHANGED
@@ -27008,6 +27008,198 @@ const rT = {
27008
27008
  `
27009
27009
  }
27010
27010
  }
27011
+ },
27012
+ withContentRows: {
27013
+ label: "With Content Rows",
27014
+ multi: !0,
27015
+ examples: {
27016
+ basic: {
27017
+ description: () => /* @__PURE__ */ o.createElement("p", null, "Filter panel alongside a list of content rows. The filter panel controls which rows are displayed based on the selected filters."),
27018
+ react: S`
27019
+ import {
27020
+ useSpsForm,
27021
+ SpsForm,
27022
+ SpsFilterPanel,
27023
+ SpsFilterPanelCap,
27024
+ SpsFilterPanelSection,
27025
+ SpsCheckbox,
27026
+ SpsContentRow,
27027
+ SpsContentRowCol,
27028
+ SpsTag,
27029
+ SpsKeyValueTag,
27030
+ SpsDropdown,
27031
+ SpsListActionBar,
27032
+ SpsButton,
27033
+ } from "@spscommerce/ds-react";
27034
+ import { ButtonKind, SpsIcon, TagKind } from "@spscommerce/ds-shared";
27035
+
27036
+ const ITEMS = [
27037
+ { id: 1, name: "Widget A", category: "Electronics", status: "Active", price: "$29.99" },
27038
+ { id: 2, name: "Gadget B", category: "Electronics", status: "Inactive", price: "$49.99" },
27039
+ { id: 3, name: "Tool C", category: "Hardware", status: "Active", price: "$19.99" },
27040
+ { id: 4, name: "Part D", category: "Hardware", status: "Active", price: "$9.99" },
27041
+ { id: 5, name: "Device E", category: "Electronics", status: "Inactive", price: "$99.99" },
27042
+ { id: 6, name: "Supply F", category: "Office", status: "Active", price: "$14.99" },
27043
+ ];
27044
+
27045
+ // Separate component for the item list display
27046
+ function ItemList({ items, selectedIds, selectItem, deselectItem, onRemove }) {
27047
+ return (
27048
+ <div className="d-flex" style={{ flexDirection: "column", gap: "0.625rem" }}>
27049
+ {items.map((item) => {
27050
+ const actions = [
27051
+ [{ label: "View Details" }, () => {}],
27052
+ [{ label: "Remove" }, () => onRemove([item.id])],
27053
+ ];
27054
+
27055
+ return (
27056
+ <SpsContentRow
27057
+ key={item.id}
27058
+ selectable
27059
+ selected={selectedIds.includes(item.id)}
27060
+ onSelectionChange={(e) => {
27061
+ if (e.target.checked) {
27062
+ selectItem(item.id);
27063
+ } else {
27064
+ deselectItem(item.id);
27065
+ }
27066
+ }}
27067
+ >
27068
+ <SpsContentRowCol>
27069
+ <div className="d-flex justify-content-between flex-wrap">
27070
+ <div>
27071
+ <div className="fs-14">{item.name}</div>
27072
+ <div>{item.category}</div>
27073
+ </div>
27074
+ <div>
27075
+ <SpsTag kind={item.status === "Active" ? TagKind.SUCCESS : TagKind.DEFAULT}>
27076
+ {item.status}
27077
+ </SpsTag>
27078
+ </div>
27079
+ </div>
27080
+ </SpsContentRowCol>
27081
+
27082
+ <SpsContentRowCol style={{ verticalAlign: "baseline" }}>
27083
+ <div className="d-flex flex-wrap">
27084
+ <SpsKeyValueTag className="mr-1 mb-1" tagKey="Price" value={item.price} />
27085
+ </div>
27086
+ </SpsContentRowCol>
27087
+
27088
+ <SpsContentRowCol widthRem={4.25}>
27089
+ <SpsDropdown icon={SpsIcon.ELLIPSES} options={actions} />
27090
+ </SpsContentRowCol>
27091
+ </SpsContentRow>
27092
+ );
27093
+ })}
27094
+ {items.length === 0 && (
27095
+ <div className="text-center text-muted py-4">
27096
+ No items match the selected filters
27097
+ </div>
27098
+ )}
27099
+ </div>
27100
+ );
27101
+ }
27102
+
27103
+ // Main component that combines the filter panel with the item list
27104
+ function FilterPanelWithContentRows() {
27105
+ const initialValues = {
27106
+ categories: {
27107
+ Electronics: false,
27108
+ Hardware: false,
27109
+ Office: false,
27110
+ },
27111
+ statuses: {
27112
+ Active: false,
27113
+ Inactive: false,
27114
+ },
27115
+ };
27116
+
27117
+ const { formValue, formMeta, updateForm } = useSpsForm(initialValues);
27118
+
27119
+ const handleClear = () => {
27120
+ updateForm(initialValues);
27121
+ formMeta.markAsPristine();
27122
+ };
27123
+
27124
+ const [selectedIds, setSelectedIds] = React.useState([]);
27125
+
27126
+ const selectItem = (id) => setSelectedIds((current) => [...current, id]);
27127
+ const deselectItem = (id) => setSelectedIds((current) => current.filter((i) => i !== id));
27128
+ const removeItems = (ids) => setSelectedIds((current) => current.filter((i) => !ids.includes(i)));
27129
+
27130
+ const selectedCategories = Object.entries(formValue.categories)
27131
+ .filter(([_, selected]) => selected)
27132
+ .map(([category]) => category);
27133
+
27134
+ const selectedStatuses = Object.entries(formValue.statuses)
27135
+ .filter(([_, selected]) => selected)
27136
+ .map(([status]) => status);
27137
+
27138
+ const filteredItems = ITEMS.filter((item) => {
27139
+ const categoryMatch = selectedCategories.length === 0 || selectedCategories.includes(item.category);
27140
+ const statusMatch = selectedStatuses.length === 0 || selectedStatuses.includes(item.status);
27141
+ return categoryMatch && statusMatch;
27142
+ });
27143
+
27144
+ return (
27145
+ <div className="sfg-row">
27146
+ <div className="sfg-col-3">
27147
+ <SpsForm formMeta={formMeta}>
27148
+ <SpsFilterPanel>
27149
+ <SpsFilterPanelCap onClear={handleClear} />
27150
+ <SpsFilterPanelSection title="Category">
27151
+ {Object.keys(initialValues.categories).map((category) => (
27152
+ <SpsCheckbox
27153
+ key={category}
27154
+ name={category}
27155
+ label={category}
27156
+ checked={formValue.categories[category]}
27157
+ formMeta={formMeta.fields.categories.fields[category]}
27158
+ />
27159
+ ))}
27160
+ </SpsFilterPanelSection>
27161
+ <SpsFilterPanelSection title="Status">
27162
+ {Object.keys(initialValues.statuses).map((status) => (
27163
+ <SpsCheckbox
27164
+ key={status}
27165
+ name={status}
27166
+ label={status}
27167
+ checked={formValue.statuses[status]}
27168
+ formMeta={formMeta.fields.statuses.fields[status]}
27169
+ />
27170
+ ))}
27171
+ </SpsFilterPanelSection>
27172
+ </SpsFilterPanel>
27173
+ </SpsForm>
27174
+ </div>
27175
+ <div className="sfg-col-9">
27176
+ <ItemList
27177
+ items={filteredItems}
27178
+ selectedIds={selectedIds}
27179
+ selectItem={selectItem}
27180
+ deselectItem={deselectItem}
27181
+ onRemove={removeItems}
27182
+ />
27183
+
27184
+ {selectedIds.length > 0 && (
27185
+ <SpsListActionBar
27186
+ itemsSelected={selectedIds.length}
27187
+ clearSelected={() => setSelectedIds([])}
27188
+ >
27189
+ <SpsButton kind={ButtonKind.DELETE} onClick={() => removeItems(selectedIds)}>
27190
+ Remove Selected
27191
+ </SpsButton>
27192
+ </SpsListActionBar>
27193
+ )}
27194
+ </div>
27195
+ </div>
27196
+ );
27197
+ }
27198
+
27199
+ render(<FilterPanelWithContentRows />);
27200
+ `
27201
+ }
27202
+ }
27011
27203
  }
27012
27204
  }, oT = {
27013
27205
  value: "string",
package/lib/index.umd.cjs CHANGED
@@ -9395,7 +9395,189 @@ Valid keys: `+JSON.stringify(Object.keys(E),null," "));var Q=U(X,ee,te,ne,W+"."
9395
9395
  </div>
9396
9396
  );
9397
9397
  }
9398
- `}}}},UE={value:"string",placeholder:"string",formMeta:"SpsFormFieldMeta<string>",onFilterChange:"ChangeEventHandler<HTMLInputElement>"};function Ls({className:e,value:t,placeholder:n,formMeta:o,onFilterChange:a,...s}){const{t:i}=Se.useWoodlandLanguage();return r.createElement("div",{className:K("sps-filter-panel__filter-box",e),...s},r.createElement(cr,{value:t,icon:A.SpsIcon.FILTER,formMeta:o,placeholder:n||i("filterPanel.filterPlaceholder",{defaultValue:"Filter options"}),onChange:a}))}Object.assign(Ls,{props:UE,displayName:"SpsFilterPanelFilterBox"});const jE={showCondition:"boolean"};function _s({showCondition:e=!0,children:t,className:n,...o}){return e?r.createElement("div",{className:K("sps-conditional-field",n),...o},t):null}Object.assign(_s,{props:jE,displayName:"SpsConditionalField"});const Wp={generalUsage:{label:"General Usage",examples:{withCheckbox:{react:S.code`
9398
+ `}}},withContentRows:{label:"With Content Rows",multi:!0,examples:{basic:{description:()=>r.createElement("p",null,"Filter panel alongside a list of content rows. The filter panel controls which rows are displayed based on the selected filters."),react:S.code`
9399
+ import {
9400
+ useSpsForm,
9401
+ SpsForm,
9402
+ SpsFilterPanel,
9403
+ SpsFilterPanelCap,
9404
+ SpsFilterPanelSection,
9405
+ SpsCheckbox,
9406
+ SpsContentRow,
9407
+ SpsContentRowCol,
9408
+ SpsTag,
9409
+ SpsKeyValueTag,
9410
+ SpsDropdown,
9411
+ SpsListActionBar,
9412
+ SpsButton,
9413
+ } from "@spscommerce/ds-react";
9414
+ import { ButtonKind, SpsIcon, TagKind } from "@spscommerce/ds-shared";
9415
+
9416
+ const ITEMS = [
9417
+ { id: 1, name: "Widget A", category: "Electronics", status: "Active", price: "$29.99" },
9418
+ { id: 2, name: "Gadget B", category: "Electronics", status: "Inactive", price: "$49.99" },
9419
+ { id: 3, name: "Tool C", category: "Hardware", status: "Active", price: "$19.99" },
9420
+ { id: 4, name: "Part D", category: "Hardware", status: "Active", price: "$9.99" },
9421
+ { id: 5, name: "Device E", category: "Electronics", status: "Inactive", price: "$99.99" },
9422
+ { id: 6, name: "Supply F", category: "Office", status: "Active", price: "$14.99" },
9423
+ ];
9424
+
9425
+ // Separate component for the item list display
9426
+ function ItemList({ items, selectedIds, selectItem, deselectItem, onRemove }) {
9427
+ return (
9428
+ <div className="d-flex" style={{ flexDirection: "column", gap: "0.625rem" }}>
9429
+ {items.map((item) => {
9430
+ const actions = [
9431
+ [{ label: "View Details" }, () => {}],
9432
+ [{ label: "Remove" }, () => onRemove([item.id])],
9433
+ ];
9434
+
9435
+ return (
9436
+ <SpsContentRow
9437
+ key={item.id}
9438
+ selectable
9439
+ selected={selectedIds.includes(item.id)}
9440
+ onSelectionChange={(e) => {
9441
+ if (e.target.checked) {
9442
+ selectItem(item.id);
9443
+ } else {
9444
+ deselectItem(item.id);
9445
+ }
9446
+ }}
9447
+ >
9448
+ <SpsContentRowCol>
9449
+ <div className="d-flex justify-content-between flex-wrap">
9450
+ <div>
9451
+ <div className="fs-14">{item.name}</div>
9452
+ <div>{item.category}</div>
9453
+ </div>
9454
+ <div>
9455
+ <SpsTag kind={item.status === "Active" ? TagKind.SUCCESS : TagKind.DEFAULT}>
9456
+ {item.status}
9457
+ </SpsTag>
9458
+ </div>
9459
+ </div>
9460
+ </SpsContentRowCol>
9461
+
9462
+ <SpsContentRowCol style={{ verticalAlign: "baseline" }}>
9463
+ <div className="d-flex flex-wrap">
9464
+ <SpsKeyValueTag className="mr-1 mb-1" tagKey="Price" value={item.price} />
9465
+ </div>
9466
+ </SpsContentRowCol>
9467
+
9468
+ <SpsContentRowCol widthRem={4.25}>
9469
+ <SpsDropdown icon={SpsIcon.ELLIPSES} options={actions} />
9470
+ </SpsContentRowCol>
9471
+ </SpsContentRow>
9472
+ );
9473
+ })}
9474
+ {items.length === 0 && (
9475
+ <div className="text-center text-muted py-4">
9476
+ No items match the selected filters
9477
+ </div>
9478
+ )}
9479
+ </div>
9480
+ );
9481
+ }
9482
+
9483
+ // Main component that combines the filter panel with the item list
9484
+ function FilterPanelWithContentRows() {
9485
+ const initialValues = {
9486
+ categories: {
9487
+ Electronics: false,
9488
+ Hardware: false,
9489
+ Office: false,
9490
+ },
9491
+ statuses: {
9492
+ Active: false,
9493
+ Inactive: false,
9494
+ },
9495
+ };
9496
+
9497
+ const { formValue, formMeta, updateForm } = useSpsForm(initialValues);
9498
+
9499
+ const handleClear = () => {
9500
+ updateForm(initialValues);
9501
+ formMeta.markAsPristine();
9502
+ };
9503
+
9504
+ const [selectedIds, setSelectedIds] = React.useState([]);
9505
+
9506
+ const selectItem = (id) => setSelectedIds((current) => [...current, id]);
9507
+ const deselectItem = (id) => setSelectedIds((current) => current.filter((i) => i !== id));
9508
+ const removeItems = (ids) => setSelectedIds((current) => current.filter((i) => !ids.includes(i)));
9509
+
9510
+ const selectedCategories = Object.entries(formValue.categories)
9511
+ .filter(([_, selected]) => selected)
9512
+ .map(([category]) => category);
9513
+
9514
+ const selectedStatuses = Object.entries(formValue.statuses)
9515
+ .filter(([_, selected]) => selected)
9516
+ .map(([status]) => status);
9517
+
9518
+ const filteredItems = ITEMS.filter((item) => {
9519
+ const categoryMatch = selectedCategories.length === 0 || selectedCategories.includes(item.category);
9520
+ const statusMatch = selectedStatuses.length === 0 || selectedStatuses.includes(item.status);
9521
+ return categoryMatch && statusMatch;
9522
+ });
9523
+
9524
+ return (
9525
+ <div className="sfg-row">
9526
+ <div className="sfg-col-3">
9527
+ <SpsForm formMeta={formMeta}>
9528
+ <SpsFilterPanel>
9529
+ <SpsFilterPanelCap onClear={handleClear} />
9530
+ <SpsFilterPanelSection title="Category">
9531
+ {Object.keys(initialValues.categories).map((category) => (
9532
+ <SpsCheckbox
9533
+ key={category}
9534
+ name={category}
9535
+ label={category}
9536
+ checked={formValue.categories[category]}
9537
+ formMeta={formMeta.fields.categories.fields[category]}
9538
+ />
9539
+ ))}
9540
+ </SpsFilterPanelSection>
9541
+ <SpsFilterPanelSection title="Status">
9542
+ {Object.keys(initialValues.statuses).map((status) => (
9543
+ <SpsCheckbox
9544
+ key={status}
9545
+ name={status}
9546
+ label={status}
9547
+ checked={formValue.statuses[status]}
9548
+ formMeta={formMeta.fields.statuses.fields[status]}
9549
+ />
9550
+ ))}
9551
+ </SpsFilterPanelSection>
9552
+ </SpsFilterPanel>
9553
+ </SpsForm>
9554
+ </div>
9555
+ <div className="sfg-col-9">
9556
+ <ItemList
9557
+ items={filteredItems}
9558
+ selectedIds={selectedIds}
9559
+ selectItem={selectItem}
9560
+ deselectItem={deselectItem}
9561
+ onRemove={removeItems}
9562
+ />
9563
+
9564
+ {selectedIds.length > 0 && (
9565
+ <SpsListActionBar
9566
+ itemsSelected={selectedIds.length}
9567
+ clearSelected={() => setSelectedIds([])}
9568
+ >
9569
+ <SpsButton kind={ButtonKind.DELETE} onClick={() => removeItems(selectedIds)}>
9570
+ Remove Selected
9571
+ </SpsButton>
9572
+ </SpsListActionBar>
9573
+ )}
9574
+ </div>
9575
+ </div>
9576
+ );
9577
+ }
9578
+
9579
+ render(<FilterPanelWithContentRows />);
9580
+ `}}}},UE={value:"string",placeholder:"string",formMeta:"SpsFormFieldMeta<string>",onFilterChange:"ChangeEventHandler<HTMLInputElement>"};function Ls({className:e,value:t,placeholder:n,formMeta:o,onFilterChange:a,...s}){const{t:i}=Se.useWoodlandLanguage();return r.createElement("div",{className:K("sps-filter-panel__filter-box",e),...s},r.createElement(cr,{value:t,icon:A.SpsIcon.FILTER,formMeta:o,placeholder:n||i("filterPanel.filterPlaceholder",{defaultValue:"Filter options"}),onChange:a}))}Object.assign(Ls,{props:UE,displayName:"SpsFilterPanelFilterBox"});const jE={showCondition:"boolean"};function _s({showCondition:e=!0,children:t,className:n,...o}){return e?r.createElement("div",{className:K("sps-conditional-field",n),...o},t):null}Object.assign(_s,{props:jE,displayName:"SpsConditionalField"});const Wp={generalUsage:{label:"General Usage",examples:{withCheckbox:{react:S.code`
9399
9581
  import {
9400
9582
  SpsCheckbox,
9401
9583
  SpsInputGroup,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@spscommerce/ds-react",
3
3
  "description": "SPS Design System React components",
4
- "version": "8.53.15",
4
+ "version": "8.53.17",
5
5
  "author": "SPS Commerce",
6
6
  "license": "UNLICENSED",
7
7
  "repository": "https://github.com/spscommerce/woodland/tree/main/packages/@spscommerce/ds-react",
@@ -46,11 +46,11 @@
46
46
  "moment-timezone": "^0.6.0",
47
47
  "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
48
48
  "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
49
- "@sps-woodland/illustrations": "8.53.15",
50
- "@spscommerce/ds-colors": "8.53.15",
51
- "@spscommerce/i18n": "8.53.15",
52
- "@spscommerce/positioning": "8.53.15",
53
- "@spscommerce/ds-shared": "8.53.15"
49
+ "@sps-woodland/illustrations": "8.53.17",
50
+ "@spscommerce/ds-colors": "8.53.17",
51
+ "@spscommerce/ds-shared": "8.53.17",
52
+ "@spscommerce/i18n": "8.53.17",
53
+ "@spscommerce/positioning": "8.53.17"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@react-stately/collections": "3.12.10",
@@ -70,12 +70,12 @@
70
70
  "raf-stub": "3.0.0",
71
71
  "react": "16.14.0",
72
72
  "react-dom": "16.14.0",
73
- "@sps-woodland/illustrations": "8.53.15",
74
- "@spscommerce/ds-shared": "8.53.15",
75
- "@spscommerce/ds-colors": "8.53.15",
76
- "@spscommerce/i18n": "8.53.15",
77
- "test": "8.53.15",
78
- "@spscommerce/positioning": "8.53.15"
73
+ "@sps-woodland/illustrations": "8.53.17",
74
+ "@spscommerce/ds-colors": "8.53.17",
75
+ "@spscommerce/ds-shared": "8.53.17",
76
+ "@spscommerce/i18n": "8.53.17",
77
+ "@spscommerce/positioning": "8.53.17",
78
+ "test": "8.53.17"
79
79
  },
80
80
  "scripts": {
81
81
  "build": "pnpm run build:js && pnpm run build:types",