diff --git a/.changeset/cyan-ants-fetch.md b/.changeset/cyan-ants-fetch.md new file mode 100644 index 000000000..4f8a38f5a --- /dev/null +++ b/.changeset/cyan-ants-fetch.md @@ -0,0 +1,5 @@ +--- +'@project44-manifest/react': minor +--- + +Adding DataTable component diff --git a/apps/website/docs/data-display/data-table.mdx b/apps/website/docs/data-display/data-table.mdx new file mode 100644 index 000000000..2e7ba5724 --- /dev/null +++ b/apps/website/docs/data-display/data-table.mdx @@ -0,0 +1,389 @@ +--- +title: DataTable +description: A rich data table component. +sidebar_custom_props: + status: 'alpha' +--- + +DataTable provides advanced functionality over Table, including sorting, pagination, column pinning, +row selection, filtering, and row expansion. + +```jsx live + +``` + +### Typescript + +DataTable leverages Typescript to provide type safety. The column definition for the table should +follow the `@tanstack/react-table` [ColumnDef](https://tanstack.com/table/v8/docs/guide/column-defs) +type. + +```jsx +import { faker } from '@faker-js/faker'; +import { ColumnDef, DataTable } from '@project44-manifest/react'; + +function Default() { + const data = [...Array.from({ length: 5 })].map(() => ({ + firstName: faker.name.firstName(), + lastName: faker.name.lastName(), + gender: faker.name.sex(), + age: faker.datatype.number(80), + address: faker.address.streetAddress(), + city: faker.address.city(), + state: faker.address.state(), + zipCode: faker.address.zipCode(), + })); + + const columns: ColumnDef<(typeof data)[0]>[] = [ + { + header: 'First Name', + accessorKey: 'firstName', + }, + { + header: 'Last Name', + accessorKey: 'lastName', + }, + { + header: 'gender', + accessorKey: 'gender', + }, + { + header: 'Age', + accessorKey: 'age', + }, + { + header: 'Address', + accessorKey: 'address', + }, + { + header: 'City', + accessorKey: 'city', + }, + { + header: 'State', + accessorKey: 'state', + }, + { + header: 'Zip', + accessorKey: 'zipCode', + }, + ]; + + return ; +} +``` + +## Usage + +### Sticky Header + +Enable sticky header with `enableStickyHeader` prop. + +```jsx live + +``` + +### Column pinning + +Pin columns to `left` and `right` using `initiateState` prop + +```jsx live + +``` + +### Loading + +Indicate loading state with `isLoading` prop + +## Props + + diff --git a/apps/website/docs/data-display/people.json b/apps/website/docs/data-display/people.json new file mode 100644 index 000000000..d2ebbffee --- /dev/null +++ b/apps/website/docs/data-display/people.json @@ -0,0 +1,52 @@ +[ + { + "firstName": "Ramona", + "lastName": "Greenfelder", + "gender": "male", + "age": 40, + "address": "93042 Chadd Loaf", + "city": "Baltimore", + "state": "New Hampshire", + "zipCode": "92745" + }, + { + "firstName": "Trent", + "lastName": "Windler", + "gender": "female", + "age": 42, + "address": "658 Emard Common", + "city": "Issacborough", + "state": "Florida", + "zipCode": "91634" + }, + { + "firstName": "Charlotte", + "lastName": "Hoppe", + "gender": "female", + "age": 68, + "address": "3835 Name Fort", + "city": "Rogahnville", + "state": "Kansas", + "zipCode": "59431-6467" + }, + { + "firstName": "Scarlett", + "lastName": "Schuster", + "gender": "male", + "age": 7, + "address": "4403 Retta Points", + "city": "Dublin", + "state": "Vermont", + "zipCode": "22208-7524" + }, + { + "firstName": "Randi", + "lastName": "Runte", + "gender": "male", + "age": 64, + "address": "635 Kassulke Rest", + "city": "McLean", + "state": "South Carolina", + "zipCode": "66430" + } +] diff --git a/data/shipments.json b/data/shipments.json new file mode 100644 index 000000000..4fb04b23e --- /dev/null +++ b/data/shipments.json @@ -0,0 +1,2987 @@ +[ + { + "carrier": "SEAU", + "destination": { + "name": "Ashdod", + "address": "Ashdod, Southern District" + }, + "identifierType": "CONT", + "identifierValue": "CAIU9136406", + "mode": "OCEAN", + "origin": { + "name": "Torrejón de Ardoz", + "address": "Torrejón de Ardoz, Madrid" + }, + "state": "In Transit" + }, + { + "carrier": "MSCU", + "destination": { + "name": "Le Havre", + "address": "Le Havre, Haute-Normandie" + }, + "identifierType": "CONT", + "identifierValue": "TCLU3075260", + "mode": "OCEAN", + "origin": { + "name": "Gebze", + "address": "Gebze, Kocaeli" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "East London", + "address": "East London, Eastern Cape" + }, + "identifierType": "CONT", + "identifierValue": "TLLU2429747", + "mode": "OCEAN", + "origin": { + "name": "Tema", + "address": "Tema, Greater Accra" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "East London", + "address": "East London, Eastern Cape" + }, + "identifierType": "CONT", + "identifierValue": "TTNU1124806", + "mode": "OCEAN", + "origin": { + "name": "Tema", + "address": "Tema, Greater Accra" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Long Beach", + "address": "Long Beach, California" + }, + "identifierType": "CONT", + "identifierValue": "SUDU6862193", + "mode": "OCEAN", + "origin": { + "name": "Tianjin (Xingang)", + "address": "Tianjin, Tianjin Shi" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Keelung", + "address": "Keelung, Taiwan" + }, + "identifierType": "CONT", + "identifierValue": "TTNU1285499", + "mode": "OCEAN", + "origin": { + "name": "Mobile", + "address": "Mobile, Alabama" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Keelung", + "address": "Keelung, Taiwan" + }, + "identifierType": "CONT", + "identifierValue": "MRKU8278162", + "mode": "OCEAN", + "origin": { + "name": "Mobile", + "address": "Mobile, Alabama" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Los Angeles", + "address": "Los Angeles, California" + }, + "identifierType": "CONT", + "identifierValue": "BEAU5184090", + "mode": "OCEAN", + "origin": { + "name": "Tianjin (Xingang)", + "address": "Tianjin, Tianjin Shi" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Los Angeles", + "address": "Los Angeles, California" + }, + "identifierType": "CONT", + "identifierValue": "CAAU5225360", + "mode": "OCEAN", + "origin": { + "name": "Tianjin (Xingang)", + "address": "Tianjin, Tianjin Shi" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Riga", + "address": "Riga, Riga" + }, + "identifierType": "CONT", + "identifierValue": "MSKU9325260", + "mode": "OCEAN", + "origin": { + "name": "Busan", + "address": "Busan, Busan" + }, + "state": "In Transit" + }, + { + "carrier": "COSCO", + "destination": { + "name": "Cartagena", + "address": "Cartagena, Bolívar" + }, + "identifierType": "CONT", + "identifierValue": "FFAU3370130", + "mode": "OCEAN", + "origin": { + "name": "Manzanillo", + "address": "Manzanillo, Colima" + }, + "state": "Completed" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Los Angeles", + "address": "Los Angeles, California" + }, + "identifierType": "CONT", + "identifierValue": "MRKU9585651", + "mode": "OCEAN", + "origin": { + "name": "Hai Phong", + "address": "Haiphong, Hải Phòng" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taichung Harbor", + "address": "Taichung, Taiwan" + }, + "identifierType": "CONT", + "identifierValue": "MSKU4149045", + "mode": "OCEAN", + "origin": { + "name": "Bremerhaven", + "address": "Bremerhaven, Bremen" + }, + "state": "In Transit" + }, + { + "carrier": "COSU", + "destination": { + "name": "Los Angeles", + "address": "Los Angeles, California" + }, + "identifierType": "CONT", + "identifierValue": "OOCU8960740", + "mode": "OCEAN", + "origin": { + "name": "Jakarta (Tanjung Priok)", + "address": "Jakarta, Jakarta Raya" + }, + "state": "In Transit" + }, + { + "carrier": "COSU", + "destination": { + "name": "Los Angeles", + "address": "Los Angeles, California" + }, + "identifierType": "CONT", + "identifierValue": "TCNU2609650", + "mode": "OCEAN", + "origin": { + "name": "Jakarta (Tanjung Priok)", + "address": "Jakarta, Jakarta Raya" + }, + "state": "In Transit" + }, + { + "carrier": "MSCU", + "destination": { + "name": "Long Beach", + "address": "Long Beach, California" + }, + "identifierType": "CONT", + "identifierValue": "FFAU2251712", + "mode": "OCEAN", + "origin": { + "name": "Dalian", + "address": "Dalian, Liaoning" + }, + "state": "In Transit" + }, + { + "carrier": "MSCU", + "destination": { + "name": "Long Beach", + "address": "Long Beach, California" + }, + "identifierType": "CONT", + "identifierValue": "MSMU2245288", + "mode": "OCEAN", + "origin": { + "name": "Dalian", + "address": "Dalian, Liaoning" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Houston", + "address": "Houston, Texas" + }, + "identifierType": "CONT", + "identifierValue": "MSKU4700008", + "mode": "OCEAN", + "origin": { + "name": "Hai Phong", + "address": "Haiphong, Hải Phòng" + }, + "state": "In Transit" + }, + { + "carrier": "MSCU", + "destination": { + "name": "Dallas", + "address": "Dallas, Texas" + }, + "identifierType": "CONT", + "identifierValue": "CAIU7649570", + "mode": "UNKNOWN", + "origin": { + "name": "Laem Chabang", + "address": "Laem Chabang, Chon Buri" + }, + "state": "In Transit" + }, + { + "carrier": "MSCU", + "destination": { + "name": "Dallas", + "address": "Dallas, Texas" + }, + "identifierType": "CONT", + "identifierValue": "TCNU8987719", + "mode": "OCEAN", + "origin": { + "name": "Laem Chabang", + "address": "Laem Chabang, Chon Buri" + }, + "state": "In Transit" + }, + { + "carrier": "MSCU", + "destination": { + "name": "Dallas", + "address": "Dallas, Texas" + }, + "identifierType": "CONT", + "identifierValue": "TCLU1860129", + "mode": "OCEAN", + "origin": { + "name": "Laem Chabang", + "address": "Laem Chabang, Chon Buri" + }, + "state": "In Transit" + }, + { + "carrier": "MSCU", + "destination": { + "name": "Dallas", + "address": "Dallas, Texas" + }, + "identifierType": "CONT", + "identifierValue": "MSDU7060383", + "mode": "OCEAN", + "origin": { + "name": "Laem Chabang", + "address": "Laem Chabang, Chon Buri" + }, + "state": "In Transit" + }, + { + "carrier": "MSCU", + "destination": { + "name": "Dallas", + "address": "Dallas, Texas" + }, + "identifierType": "CONT", + "identifierValue": "BSIU9084247", + "mode": "OCEAN", + "origin": { + "name": "Laem Chabang", + "address": "Laem Chabang, Chon Buri" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Gdansk", + "address": "Gdańsk, Pomeranian Voivodeship" + }, + "identifierType": "CONT", + "identifierValue": "SUDU1449464", + "mode": "UNKNOWN", + "origin": { + "name": "Busan", + "address": "Busan, Busan" + }, + "state": "In Transit" + }, + { + "carrier": "Maersk", + "destination": { + "name": "Busan", + "address": "Busan, Busan" + }, + "identifierType": "CONT", + "identifierValue": "MRKU4759200", + "mode": "OCEAN", + "origin": { + "name": "Chennai", + "address": "Chennai, Tamil Nadu" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MSKU1498763", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MRKU3742579", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MRKU2374765", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MRSU6370082", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MSKU8695189", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MSKU1232238", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MRSU3585087", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MRKU5428660", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "HASU5083220", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MRSU3274803", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MRKU6366114", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MSKU0093539", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "PONU8261897", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MRKU2919823", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "PONU8058750", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MRKU5642054", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MRKU5256299", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "HASU4986485", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MRSU3307851", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Nansha", + "address": "Nansha, Guangdong" + }, + "identifierType": "CONT", + "identifierValue": "MRKU2082803", + "mode": "UNKNOWN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Auckland", + "address": "Auckland, Auckland" + }, + "identifierType": "CONT", + "identifierValue": "FSCU9740809", + "mode": "OCEAN", + "origin": { + "name": "Ho Chi Minh", + "address": "Ho Chi Minh City, Ho Chi Minh City" + }, + "state": "In Transit" + }, + { + "carrier": "MSC", + "destination": { + "name": "Bremerhaven", + "address": "Bremerhaven, Bremen" + }, + "identifierType": "CONT", + "identifierValue": "TCNU6975278", + "mode": "OCEAN", + "origin": { + "name": "Muhamad Bin Qasim", + "address": "Karachi, Sindh" + }, + "state": "At Stop" + }, + { + "carrier": "MSC", + "destination": { + "name": "Bremerhaven", + "address": "Bremerhaven, Bremen" + }, + "identifierType": "CONT", + "identifierValue": "MEDU8610912", + "mode": "OCEAN", + "origin": { + "name": "Muhamad Bin Qasim", + "address": "Karachi, Sindh" + }, + "state": "At Stop" + }, + { + "carrier": "MSC", + "destination": { + "name": "Bremerhaven", + "address": "Bremerhaven, Bremen" + }, + "identifierType": "CONT", + "identifierValue": "TCNU1606338", + "mode": "OCEAN", + "origin": { + "name": "Muhamad Bin Qasim", + "address": "Karachi, Sindh" + }, + "state": "At Stop" + }, + { + "carrier": "ONEY", + "destination": { + "name": "Laem Chabang", + "address": "Laem Chabang, Chon Buri" + }, + "identifierType": "CONT", + "identifierValue": "GCXU2243023", + "mode": "OCEAN", + "origin": { + "name": "Garhi Harsaru", + "address": "Garhi Harsaru, Haryana" + }, + "state": "In Transit" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "2551801790626", + "mode": "LTL", + "origin": { + "name": "DC SOUTH- VERIZON / CTDI", + "address": "HASLET, TX" + }, + "state": "Completed" + }, + { + "carrier": "SEFL", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "3511795932578", + "mode": "LTL", + "origin": { + "name": "DC Etna", + "address": "Pataskala, OH" + }, + "state": "Completed" + }, + { + "carrier": "SAIA", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, TN" + }, + "identifierType": "BOL", + "identifierValue": "8991823041145", + "mode": "LTL", + "origin": { + "name": "Ascent Battery Supply", + "address": "Glendale, WI" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "5805671024726", + "mode": "LTL", + "origin": { + "name": "BISSELL Homecare Inc. c/o Ryder", + "address": "Rincon, GA" + }, + "state": "Completed" + }, + { + "carrier": "RDWY", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, MS" + }, + "identifierType": "BOL", + "identifierValue": "4070021987557", + "mode": "LTL", + "origin": { + "name": "ACTION AUTOMATION", + "address": "ALSIP, IL" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "8652543016132", + "mode": "LTL", + "origin": { + "name": "Novex Supply Chain", + "address": "MEMPHIS, TN" + }, + "state": "Completed" + }, + { + "carrier": "FXFE", + "destination": { + "name": "Sahara - Fulton DC", + "address": "FULTON, MS" + }, + "identifierType": "BOL", + "identifierValue": "8140675078381", + "mode": "LTL", + "origin": { + "name": "NUPI AMERICAS", + "address": "EARLY BRANCH, SC" + }, + "state": "Completed" + }, + { + "carrier": "EXLA", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "7197342995053", + "mode": "LTL", + "origin": { + "name": "Novex Supply Chain", + "address": "MEMPHIS, TN" + }, + "state": "Completed" + }, + { + "carrier": "EXLA", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "9702679435867", + "mode": "LTL", + "origin": { + "name": "BISSELL Homecare Inc. c/o DAMCO Distribution", + "address": "Elwood, IL" + }, + "state": "Completed" + }, + { + "carrier": "AACT", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "5867936551790", + "mode": "LTL", + "origin": { + "name": "CARPENTER AND PATERSON", + "address": "WESTWEGO, LA" + }, + "state": "Completed" + }, + { + "carrier": "EXLA", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "6506661166913", + "mode": "LTL", + "origin": { + "name": "CARPENTER AND PATERSON", + "address": "WESTWEGO, LA" + }, + "state": "Completed" + }, + { + "carrier": "EXLA", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "880463178185", + "mode": "LTL", + "origin": { + "name": "HAMMOND MACHINE WORKS, INC.", + "address": "HAMMOND, IN" + }, + "state": "Completed" + }, + { + "carrier": "RDWY", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "737807330728", + "mode": "LTL", + "origin": { + "name": "JS Products, Inc. ", + "address": "GROVEPORT, OH" + }, + "state": "Completed" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "UETU5036570", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "TCLU5442981", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "HASU4865441", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "TCLU5362778", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "PONU8131390", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "SUDU5917706", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MSKU0500423", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MSKU1082159", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MSKU8696164", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MRKU3416227", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "TCKU7911714", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MRSU3724367", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "TRHU4845936", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MRKU3650451", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MIEU3016010", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MSKU9506567", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "SUDU6716049", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MSKU1430824", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MRKU4227491", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "SUDU6530434", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MIEU0022132", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "TCNU1472347", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "HASU4516455", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "SEKU4590589", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "TGHU9885966", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MSKU0477853", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MSKU1777855", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "HASU4436004", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MRKU2315361", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "SUDU8900501", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "CAIU8220960", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "MRKU3772676", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "PONU8059551", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "MAEU", + "destination": { + "name": "Taicang", + "address": "Taicang, Jiangsu Sheng" + }, + "identifierType": "CONT", + "identifierValue": "SUDU8971660", + "mode": "OCEAN", + "origin": { + "name": "Durban", + "address": "Durban, KwaZulu-Natal" + }, + "state": "In Transit" + }, + { + "carrier": "ODFL", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "2067100371112", + "mode": "LTL", + "origin": { + "name": "BUTTER BUDS FOOD INGREDIENTS", + "address": "RACINE, WI" + }, + "state": "Completed" + }, + { + "carrier": "EXLA", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "2329874225654", + "mode": "LTL", + "origin": { + "name": "JS Products - Columbus", + "address": "GROVEPORT, OH" + }, + "state": "Completed" + }, + { + "carrier": "UPGF", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "6079891527843", + "mode": "LTL", + "origin": { + "name": "EO Products - Kerner", + "address": "SAN RAFAEL, CA" + }, + "state": "Completed" + }, + { + "carrier": "UPGF", + "destination": { + "name": "Sahara - Ardmore DC", + "address": "ARDMORE, OK" + }, + "identifierType": "BOL", + "identifierValue": "5312239843825", + "mode": "LTL", + "origin": { + "name": "BISSELL Homecare Inc. c/o Shipper's Warehouse", + "address": "Lancaster, TX" + }, + "state": "Completed" + }, + { + "carrier": "RLCA", + "destination": { + "name": "Sahara - Fulton DC", + "address": "FULTON, MO" + }, + "identifierType": "BOL", + "identifierValue": "2600856731775", + "mode": "LTL", + "origin": { + "name": "Unknown", + "address": "CHATTANOOGA, TN" + }, + "state": "Completed" + }, + { + "carrier": "SEFL", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "8783299136687", + "mode": "LTL", + "origin": { + "name": "BUTTER BUDS FOOD INGREDIENTS", + "address": "RACINE, WI" + }, + "state": "Completed" + }, + { + "carrier": "RLCA", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "6731532351832", + "mode": "LTL", + "origin": { + "name": "ASPEN SURGICAL", + "address": "CALEDONIA, MI" + }, + "state": "Completed" + }, + { + "carrier": "SEFL", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "4637490959642", + "mode": "LTL", + "origin": { + "name": "SAN BERNARDINO DISTRIBUTION CENTER", + "address": "SAN BERNARDINO, CA" + }, + "state": "Completed" + }, + { + "carrier": "PITD", + "destination": { + "name": "Sahara - Fulton DC", + "address": "FULTON, MO" + }, + "identifierType": "BOL", + "identifierValue": "3185694796600", + "mode": "LTL", + "origin": { + "name": "MATSON (SAVANNAH) PREPAID", + "address": "POOLER, GA" + }, + "state": "Completed" + }, + { + "carrier": "EXLA", + "destination": { + "name": "Sahara - Fulton DC", + "address": "FULTON, MO" + }, + "identifierType": "BOL", + "identifierValue": "9467268874462", + "mode": "LTL", + "origin": { + "name": "DHL CHICAGO", + "address": "KANKAKEE, IL" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Fulton DC", + "address": "FULTON, MO" + }, + "identifierType": "BOL", + "identifierValue": "5658409626134", + "mode": "LTL", + "origin": { + "name": "BISSELL Homecare Inc. c/o DAMCO Distribution", + "address": "Elwood, IL" + }, + "state": "Completed" + }, + { + "carrier": "ONE", + "destination": { + "name": "San Antonio", + "address": "San Antonio, Valparaíso" + }, + "identifierType": "CONT", + "identifierValue": "TLLU5478154", + "mode": "OCEAN", + "origin": { + "name": "Port Klang", + "address": "Klang, Selangor" + }, + "state": "Completed" + }, + { + "carrier": "AACT", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "7416594004922", + "mode": "LTL", + "origin": { + "name": "BUDA", + "address": "BUDA, TX" + }, + "state": "Completed" + }, + { + "carrier": "RLCA", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "2369558642478", + "mode": "LTL", + "origin": { + "name": "Iron Ridge suite# 170", + "address": "ATLANTA, GA" + }, + "state": "Completed" + }, + { + "carrier": "PITD", + "destination": { + "name": "Sahara - Ardmore DC", + "address": "ARDMORE, OK" + }, + "identifierType": "BOL", + "identifierValue": "1867078919620", + "mode": "LTL", + "origin": { + "name": "APHENA PHARMA SOLUTIONS-MD", + "address": "EASTON, MD" + }, + "state": "Completed" + }, + { + "carrier": "FXFE", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "731286899184", + "mode": "LTL", + "origin": { + "name": "DC Etna", + "address": "Pataskala, OH" + }, + "state": "Completed" + }, + { + "carrier": "SAIA", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, GA" + }, + "identifierType": "BOL", + "identifierValue": "2815347325571", + "mode": "LTL", + "origin": { + "name": "Unknown", + "address": "CHATTANOOGA, TN" + }, + "state": "Completed" + }, + { + "carrier": "FXFE", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, TN" + }, + "identifierType": "BOL", + "identifierValue": "227943675990", + "mode": "LTL", + "origin": { + "name": "Ascent Battery Supply", + "address": "Glendale, WI" + }, + "state": "Completed" + }, + { + "carrier": "PITD", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, MS" + }, + "identifierType": "BOL", + "identifierValue": "1282494421724", + "mode": "LTL", + "origin": { + "name": "ACTION AUTOMATION", + "address": "ALSIP, IL" + }, + "state": "Completed" + }, + { + "carrier": "UPGF", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "2644584918766", + "mode": "LTL", + "origin": { + "name": "JAMES C WHITE COMPANY INC", + "address": "GREENVILLE, SC" + }, + "state": "Completed" + }, + { + "carrier": "RLCA", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "2425683852399", + "mode": "LTL", + "origin": { + "name": "Cerrowire - Hartselle", + "address": "HARTSELLE, AL" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, MI" + }, + "identifierType": "BOL", + "identifierValue": "6702505015832", + "mode": "LTL", + "origin": { + "name": "Hayward FlowControl Clemmons", + "address": "CLEMMONS, NC" + }, + "state": "Completed" + }, + { + "carrier": "RDWY", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "2008274745655", + "mode": "LTL", + "origin": { + "name": "SOUTHWEST DISTRIBUTION CENTER", + "address": "FORT WORTH, TX" + }, + "state": "Completed" + }, + { + "carrier": "SEFL", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "5834110043350", + "mode": "LTL", + "origin": { + "name": "HAMMOND MACHINE WORKS, INC.", + "address": "HAMMOND, IN" + }, + "state": "Completed" + }, + { + "carrier": "AACT", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "4532543361119", + "mode": "LTL", + "origin": { + "name": "Cerrowire - Hartselle", + "address": "HARTSELLE, AL" + }, + "state": "Completed" + }, + { + "carrier": "PITD", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "4417484845565", + "mode": "LTL", + "origin": { + "name": "HAMMOND MACHINE WORKS, INC.", + "address": "HAMMOND, IN" + }, + "state": "Completed" + }, + { + "carrier": "PITD", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "5236551756538", + "mode": "LTL", + "origin": { + "name": "NICKEY MEMPHIS", + "address": "MEMPHIS, TN" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "6190433882425", + "mode": "LTL", + "origin": { + "name": "BISSELL Homecare Inc. c/o Ryder", + "address": "Rincon, GA" + }, + "state": "Completed" + }, + { + "carrier": "SAIA", + "destination": { + "name": "Sahara - Ardmore DC", + "address": "ARDMORE, OK" + }, + "identifierType": "BOL", + "identifierValue": "9246758439457", + "mode": "LTL", + "origin": { + "name": "PADC / MUSA FACILITY MATTEL", + "address": "JONESTOWN, PA" + }, + "state": "Completed" + }, + { + "carrier": "PITD", + "destination": { + "name": "Sahara - Ardmore DC", + "address": "ARDMORE, OK" + }, + "identifierType": "BOL", + "identifierValue": "2600524839296", + "mode": "LTL", + "origin": { + "name": "PADC / MUSA FACILITY MATTEL", + "address": "JONESTOWN, PA" + }, + "state": "Completed" + }, + { + "carrier": "PITD", + "destination": { + "name": "Sahara - Fulton DC", + "address": "FULTON, MO" + }, + "identifierType": "BOL", + "identifierValue": "2792799991406", + "mode": "LTL", + "origin": { + "name": "Unknown", + "address": "CHATTANOOGA, TN" + }, + "state": "Completed" + }, + { + "carrier": "ODFL", + "destination": { + "name": "Sahara - Ardmore DC", + "address": "ARDMORE, OK" + }, + "identifierType": "BOL", + "identifierValue": "5761489801167", + "mode": "LTL", + "origin": { + "name": "PADC / MUSA FACILITY MATTEL", + "address": "JONESTOWN, PA" + }, + "state": "Completed" + }, + { + "carrier": "ODFL", + "destination": { + "name": "Sahara - Fulton DC", + "address": "FULTON, MO" + }, + "identifierType": "BOL", + "identifierValue": "6472153316399", + "mode": "LTL", + "origin": { + "name": "MATSON (SAVANNAH) PREPAID", + "address": "POOLER, GA" + }, + "state": "Completed" + }, + { + "carrier": "EXLA", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "7045608353748", + "mode": "LTL", + "origin": { + "name": "GRAPHIC PACKAGING INTL", + "address": "MACON, GA" + }, + "state": "Completed" + }, + { + "carrier": "SEFL", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "9049965713570", + "mode": "LTL", + "origin": { + "name": "Novex Supply Chain", + "address": "MEMPHIS, TN" + }, + "state": "Completed" + }, + { + "carrier": "EXLA", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "6989102471519", + "mode": "LTL", + "origin": { + "name": "BISSELL Homecare Inc. c/o DAMCO Distribution", + "address": "Elwood, IL" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "1528009024847", + "mode": "LTL", + "origin": { + "name": "BISSELL Homecare Inc. c/o Shipper's Warehouse", + "address": "Lancaster, TX" + }, + "state": "Completed" + }, + { + "carrier": "UPGF", + "destination": { + "name": "Sahara - Ardmore DC", + "address": "ARDMORE, OK" + }, + "identifierType": "BOL", + "identifierValue": "5504044788490", + "mode": "LTL", + "origin": { + "name": "APHENA PHARMA SOLUTIONS-MD", + "address": "EASTON, MD" + }, + "state": "Completed" + }, + { + "carrier": "EXLA", + "destination": { + "name": "Sahara - Ardmore DC", + "address": "ARDMORE, OK" + }, + "identifierType": "BOL", + "identifierValue": "1350806249561", + "mode": "LTL", + "origin": { + "name": "APHENA PHARMA SOLUTIONS-MD", + "address": "EASTON, MD" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Ardmore DC", + "address": "ARDMORE, OK" + }, + "identifierType": "BOL", + "identifierValue": "2601870637647", + "mode": "LTL", + "origin": { + "name": "ELECTROLUX DALLAS RDC", + "address": "LANCASTER, TX" + }, + "state": "Completed" + }, + { + "carrier": "SAIA", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, WY" + }, + "identifierType": "BOL", + "identifierValue": "8156329874496", + "mode": "LTL", + "origin": { + "name": "SAN BERNARDINO DISTRIBUTION CENTER", + "address": "SAN BERNARDINO, CA" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, GA" + }, + "identifierType": "BOL", + "identifierValue": "7333924312832", + "mode": "LTL", + "origin": { + "name": "ascent consumer products c/o Allrite Logistics - DOCK 15-18", + "address": "COLUMBUS, OH" + }, + "state": "Completed" + }, + { + "carrier": "FXFE", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "7685107380247", + "mode": "LTL", + "origin": { + "name": "NICKEY MEMPHIS", + "address": "MEMPHIS, TN" + }, + "state": "Completed" + }, + { + "carrier": "UPGF", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "5175383123735", + "mode": "LTL", + "origin": { + "name": "EO Products - Kerner", + "address": "SAN RAFAEL, CA" + }, + "state": "Completed" + }, + { + "carrier": "ODFL", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, WI" + }, + "identifierType": "BOL", + "identifierValue": "8777937745714", + "mode": "LTL", + "origin": { + "name": "NESTLE DISTRIBUTION", + "address": "DEKALB, IL" + }, + "state": "Completed" + }, + { + "carrier": "ODFL", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, WA" + }, + "identifierType": "BOL", + "identifierValue": "6100944850951", + "mode": "LTL", + "origin": { + "name": "Eagle Foundry", + "address": "Eagle Creek, OR" + }, + "state": "Completed" + }, + { + "carrier": "CRFR", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "San Antonio, TX" + }, + "identifierType": "BOL", + "identifierValue": "539978869649", + "mode": "TRUCKLOAD", + "origin": { + "name": "C G Roxane LLC", + "address": "Benton, TN" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Fulton DC", + "address": "FULTON, KY" + }, + "identifierType": "BOL", + "identifierValue": "6574091774621", + "mode": "LTL", + "origin": { + "name": "Everidge - Greeneville*", + "address": "GREENEVILLE, TN" + }, + "state": "Completed" + }, + { + "carrier": "AACT", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, TN" + }, + "identifierType": "BOL", + "identifierValue": "6965735243224", + "mode": "LTL", + "origin": { + "name": "Ascent Battery Supply", + "address": "Glendale, WI" + }, + "state": "Completed" + }, + { + "carrier": "EXLA", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "4196372143472", + "mode": "LTL", + "origin": { + "name": "Cerrowire - Hartselle", + "address": "HARTSELLE, AL" + }, + "state": "Completed" + }, + { + "carrier": "ODFL", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "7530393454355", + "mode": "LTL", + "origin": { + "name": "ELECTROLUX DALLAS RDC", + "address": "LANCASTER, TX" + }, + "state": "Completed" + }, + { + "carrier": "RDWY", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "5027109776646", + "mode": "LTL", + "origin": { + "name": "HAMMOND MACHINE WORKS, INC.", + "address": "HAMMOND, IN" + }, + "state": "Completed" + }, + { + "carrier": "RLCA", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "5067896391902", + "mode": "LTL", + "origin": { + "name": "TRINITY PARTS AND COMPONENTS", + "address": "FORT WORTH, TX" + }, + "state": "Completed" + }, + { + "carrier": "EXLA", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "7480841463237", + "mode": "LTL", + "origin": { + "name": "Cerrowire - Hartselle", + "address": "HARTSELLE, AL" + }, + "state": "Completed" + }, + { + "carrier": "RLCA", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "2462130326066", + "mode": "LTL", + "origin": { + "name": "BISSELL Homecare Inc. c/o Ryder", + "address": "Rincon, GA" + }, + "state": "Completed" + }, + { + "carrier": "KNIG", + "destination": { + "name": "Sahara - Jackson DC", + "address": "Jackson, GA" + }, + "identifierType": "BOL", + "identifierValue": "403034690747", + "mode": "TRUCKLOAD", + "origin": { + "name": "First Quality Consumer PR", + "address": "Macon, GA" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Ardmore DC", + "address": "ARDMORE, OK" + }, + "identifierType": "BOL", + "identifierValue": "1044060423575", + "mode": "LTL", + "origin": { + "name": "SOUTHWEST DISTRIBUTION CENTER", + "address": "FORT WORTH, TX" + }, + "state": "Completed" + }, + { + "carrier": "UPGF", + "destination": { + "name": "Sahara - Ardmore DC", + "address": "ARDMORE, OK" + }, + "identifierType": "BOL", + "identifierValue": "8934275497540", + "mode": "LTL", + "origin": { + "name": "SOUTHWEST DISTRIBUTION CENTER", + "address": "FORT WORTH, TX" + }, + "state": "Completed" + }, + { + "carrier": "SEFL", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, WY" + }, + "identifierType": "BOL", + "identifierValue": "9661232033591", + "mode": "LTL", + "origin": { + "name": "Greenheck Fan Corporation", + "address": "SCHOFIELD, WI" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Fulton DC", + "address": "FULTON, MO" + }, + "identifierType": "BOL", + "identifierValue": "9935984403653", + "mode": "LTL", + "origin": { + "name": "WORTHINGTON CYLINDER CORP", + "address": "COLUMBUS, OH" + }, + "state": "Completed" + }, + { + "carrier": "SAIA", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "1338816096573", + "mode": "LTL", + "origin": { + "name": "SAN BERNARDINO DISTRIBUTION CENTER", + "address": "SAN BERNARDINO, CA" + }, + "state": "Completed" + }, + { + "carrier": "UPGF", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "7987817652417", + "mode": "LTL", + "origin": { + "name": "M&W Warehouse", + "address": "Morrow, GA" + }, + "state": "Completed" + }, + { + "carrier": "AACT", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "1708594193861", + "mode": "LTL", + "origin": { + "name": "FD", + "address": "FORT WORTH, TX" + }, + "state": "Completed" + }, + { + "carrier": "RDWY", + "destination": { + "name": "Sahara - Fulton DC", + "address": "FULTON, MO" + }, + "identifierType": "BOL", + "identifierValue": "9217431722669", + "mode": "LTL", + "origin": { + "name": "Unknown", + "address": "CHATTANOOGA, TN" + }, + "state": "Completed" + }, + { + "carrier": "ODFL", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "1948155375081", + "mode": "LTL", + "origin": { + "name": "Daktronics HSPR Shipping", + "address": "BROOKINGS, SD" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "7142018839826", + "mode": "LTL", + "origin": { + "name": "BISSELL Homecare Inc. c/o Shipper's Warehouse", + "address": "Lancaster, TX" + }, + "state": "Completed" + }, + { + "carrier": "KNIG", + "destination": { + "name": "Sahara - Zanesville DC", + "address": "Zanesville, OH" + }, + "identifierType": "BOL", + "identifierValue": "612380555463", + "mode": "TRUCKLOAD", + "origin": { + "name": "Woeber Mustard MFG Co", + "address": "Springfield, OH" + }, + "state": "Completed" + }, + { + "carrier": "PRIJ", + "destination": { + "name": "SAH963345", + "address": "Shenandoah, PA" + }, + "identifierType": "BOL", + "identifierValue": "162127490483", + "mode": "TRUCKLOAD", + "origin": { + "name": "Sahara - Bethel DC", + "address": "Bethel, PA" + }, + "state": "Completed" + }, + { + "carrier": "KNIG", + "destination": { + "name": "SAH927002", + "address": "Orange City, FL" + }, + "identifierType": "BOL", + "identifierValue": "706308620011", + "mode": "TRUCKLOAD", + "origin": { + "name": "Sahara - Alachua DC", + "address": "Alachua, FL" + }, + "state": "Completed" + }, + { + "carrier": "KNIG", + "destination": { + "name": "Sahara - Longview DC", + "address": "Longview, TX" + }, + "identifierType": "BOL", + "identifierValue": "701288554659", + "mode": "TRUCKLOAD", + "origin": { + "name": "Superbag Corporation", + "address": "Houston, TX" + }, + "state": "Completed" + }, + { + "carrier": "CRFR", + "destination": { + "name": "Sahara - Fulton DC", + "address": "Fulton, MO" + }, + "identifierType": "BOL", + "identifierValue": "907718934572", + "mode": "TRUCKLOAD", + "origin": { + "name": "Awesome Products Inc", + "address": "West Memphis, AR" + }, + "state": "Completed" + }, + { + "carrier": "KNIG", + "destination": { + "name": "Sahara - Bethel DC", + "address": "Bethel, PA" + }, + "identifierType": "BOL", + "identifierValue": "468989009469", + "mode": "TRUCKLOAD", + "origin": { + "name": "Sterilite-Edi", + "address": "Massillon, OH" + }, + "state": "Completed" + }, + { + "carrier": "PRIJ", + "destination": { + "name": "Sahara - Amsterdam DC", + "address": "Amsterdam, NY" + }, + "identifierType": "BOL", + "identifierValue": "923002662829", + "mode": "TRUCKLOAD", + "origin": { + "name": "Sahara - Amsterdam DC", + "address": "Amsterdam, NY" + }, + "state": "Completed" + }, + { + "carrier": "KNIG", + "destination": { + "name": "SAH558725", + "address": "Greenwood, MS" + }, + "identifierType": "BOL", + "identifierValue": "748630919359", + "mode": "TRUCKLOAD", + "origin": { + "name": "Sahara - Indianola DC", + "address": "Indianola, MS" + }, + "state": "Completed" + }, + { + "carrier": "KNIG", + "destination": { + "name": "Sahara - Indianola DC", + "address": "Indianola, MS" + }, + "identifierType": "BOL", + "identifierValue": "1667637258", + "mode": "TRUCKLOAD", + "origin": { + "name": "Igloo", + "address": "Katy, TX" + }, + "state": "Completed" + }, + { + "carrier": "PRIJ", + "destination": { + "name": "Sahara - Janesville DC", + "address": "Janesville, WI" + }, + "identifierType": "BOL", + "identifierValue": "961583314780", + "mode": "TRUCKLOAD", + "origin": { + "name": "AJM Packaging Corp", + "address": "Brownstown Township, MI" + }, + "state": "Completed" + }, + { + "carrier": "–", + "destination": { + "name": "Telford", + "address": "Telford, England" + }, + "identifierType": "BOL", + "identifierValue": "690388275589", + "mode": "TRUCKLOAD", + "origin": { + "name": "Birmingham", + "address": "Birmingham, England" + }, + "state": "Completed" + }, + { + "carrier": "KNIG", + "destination": { + "name": "Sahara - Amsterdam DC", + "address": "Amsterdam, NY" + }, + "identifierType": "BOL", + "identifierValue": "17065945071", + "mode": "TRUCKLOAD", + "origin": { + "name": "Dinesol Plastics Inc", + "address": "Youngstown, OH" + }, + "state": "Completed" + }, + { + "carrier": "WENP", + "destination": { + "name": "Sahara - Amsterdam DC", + "address": "Amsterdam, NY" + }, + "identifierType": "BOL", + "identifierValue": "585965506533", + "mode": "TRUCKLOAD", + "origin": { + "name": "Domino Foods Inc", + "address": "Buffalo, NY" + }, + "state": "Completed" + }, + { + "carrier": "SAIA", + "destination": { + "name": "Sahara - Ardmore DC", + "address": "ARDMORE, OK" + }, + "identifierType": "BOL", + "identifierValue": "38939716071", + "mode": "LTL", + "origin": { + "name": "NICKEY MEMPHIS", + "address": "MEMPHIS, TN" + }, + "state": "Completed" + }, + { + "carrier": "RDWY", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "7313317918625", + "mode": "LTL", + "origin": { + "name": "NICKEY MEMPHIS", + "address": "MEMPHIS, TN" + }, + "state": "Completed" + }, + { + "carrier": "–", + "destination": { + "name": "Cambrai", + "address": "Cambrai, Hauts-de-France" + }, + "identifierType": "BOL", + "identifierValue": "953492379285", + "mode": "TRUCKLOAD", + "origin": { + "name": "Antwerp", + "address": "Antwerpen, Vlaanderen" + }, + "state": "Completed" + }, + { + "carrier": "WENP", + "destination": { + "name": "Sahara - Lebec DC", + "address": "Lebec, CA" + }, + "identifierType": "BOL", + "identifierValue": "438509245735", + "mode": "TRUCKLOAD", + "origin": { + "name": "Kraft", + "address": "Fontana, CA" + }, + "state": "Completed" + }, + { + "carrier": "RDWY", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "105533677134", + "mode": "LTL", + "origin": { + "name": "NESTLE DC ATLANTA GA", + "address": "MCDONOUGH, GA" + }, + "state": "Completed" + }, + { + "carrier": "USXI", + "destination": { + "name": "Sahara - Alachua DC", + "address": "Alachua, FL" + }, + "identifierType": "BOL", + "identifierValue": "859502766380", + "mode": "TRUCKLOAD", + "origin": { + "name": "Awesome Products Inc", + "address": "Mt Airy, NC" + }, + "state": "Completed" + }, + { + "carrier": "–", + "destination": { + "name": "Milano", + "address": "Milano, Lombardia" + }, + "identifierType": "BOL", + "identifierValue": "451292975001", + "mode": "TRUCKLOAD", + "origin": { + "name": "La Spezia", + "address": "La Spezia, Liguria" + }, + "state": "Completed" + }, + { + "carrier": "RDWY", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, TN" + }, + "identifierType": "BOL", + "identifierValue": "3503968363698", + "mode": "LTL", + "origin": { + "name": "Ascent Battery Supply", + "address": "Glendale, WI" + }, + "state": "Completed" + }, + { + "carrier": "USXI", + "destination": { + "name": "Sahara - Indianola DC", + "address": "Indianola, MS" + }, + "identifierType": "BOL", + "identifierValue": "937789984397", + "mode": "TRUCKLOAD", + "origin": { + "name": "C G Roxane LLC", + "address": "Benton, TN" + }, + "state": "Completed" + }, + { + "carrier": "FXFE", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "7383788706242", + "mode": "LTL", + "origin": { + "name": "SAFERACK LLC", + "address": "ANDREWS, SC" + }, + "state": "Completed" + }, + { + "carrier": "EXLA", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "5649810205566", + "mode": "LTL", + "origin": { + "name": "BISSELL Homecare Inc. c/o DAMCO Distribution", + "address": "Elwood, IL" + }, + "state": "Completed" + }, + { + "carrier": "WENP", + "destination": { + "name": "SAH350621", + "address": "Columbia, LA" + }, + "identifierType": "BOL", + "identifierValue": "382834213063", + "mode": "TRUCKLOAD", + "origin": { + "name": "Sahara - Longview DC", + "address": "Longview, TX" + }, + "state": "Completed" + }, + { + "carrier": "SEFL", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "5726424970484", + "mode": "LTL", + "origin": { + "name": "TRINITY PARTS AND COMPONENTS", + "address": "FORT WORTH, TX" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - San Antonio DC", + "address": "SAN ANTONIO, TX" + }, + "identifierType": "BOL", + "identifierValue": "3786612047803", + "mode": "LTL", + "origin": { + "name": "SOUTHWEST DISTRIBUTION CENTER", + "address": "FORT WORTH, TX" + }, + "state": "Completed" + }, + { + "carrier": "ODFL", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "561467132812", + "mode": "LTL", + "origin": { + "name": "ELECTROLUX DALLAS RDC", + "address": "LANCASTER, TX" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "5575583690182", + "mode": "LTL", + "origin": { + "name": "NFI (ELWOOD) PREPAID", + "address": "ELWOOD, IL" + }, + "state": "Completed" + }, + { + "carrier": "RLCA", + "destination": { + "name": "Sahara - Alachua DC", + "address": "ALACHUA, FL" + }, + "identifierType": "BOL", + "identifierValue": "1381273200480", + "mode": "LTL", + "origin": { + "name": "WD JACKSONVILLE RDC 4181", + "address": "JACKSONVILLE, FL" + }, + "state": "Completed" + }, + { + "carrier": "SAIA", + "destination": { + "name": "Sahara - Jackson DC", + "address": "JACKSON, CA" + }, + "identifierType": "BOL", + "identifierValue": "6891101872643", + "mode": "LTL", + "origin": { + "name": "EMA ONTARIO FDC", + "address": "ONTARIO, CA" + }, + "state": "Completed" + }, + { + "carrier": "RLCA", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "8754319110343", + "mode": "LTL", + "origin": { + "name": "JS Products, Inc. ", + "address": "GROVEPORT, OH" + }, + "state": "Completed" + }, + { + "carrier": "RDWY", + "destination": { + "name": "Sahara - Janesville DC", + "address": "JANESVILLE, WI" + }, + "identifierType": "BOL", + "identifierValue": "735648502813", + "mode": "LTL", + "origin": { + "name": "JS Products", + "address": "LAS VEGAS, NV" + }, + "state": "Completed" + }, + { + "carrier": "ODFL", + "destination": { + "name": "Sahara - Longview DC", + "address": "LONGVIEW, TX" + }, + "identifierType": "BOL", + "identifierValue": "755255718393", + "mode": "LTL", + "origin": { + "name": "TRINITY PARTS AND COMPONENTS", + "address": "FORT WORTH, TX" + }, + "state": "Completed" + }, + { + "carrier": "–", + "destination": { + "name": "Sahara - Erfurt DC", + "address": "Erfurt, Thüringen" + }, + "identifierType": "BOL", + "identifierValue": "839383474470", + "mode": "TRUCKLOAD", + "origin": { + "name": "Whirlpool Company Polska SP. Z O. O.", + "address": "Radomsko, Woj. Łódzkie" + }, + "state": "Completed" + }, + { + "carrier": "ABFS", + "destination": { + "name": "Sahara - Ardmore DC", + "address": "ARDMORE, OK" + }, + "identifierType": "BOL", + "identifierValue": "5418253942107", + "mode": "LTL", + "origin": { + "name": "SOUTHWEST DISTRIBUTION CENTER", + "address": "FORT WORTH, TX" + }, + "state": "Completed" + } +] diff --git a/package.json b/package.json index a2b4fd057..372014358 100644 --- a/package.json +++ b/package.json @@ -69,5 +69,8 @@ "packageManager": "yarn@3.3.1", "engines": { "node": "18.16.1" + }, + "devDependencies": { + "@faker-js/faker": "^7.6.0" } } diff --git a/packages/react/docs.json b/packages/react/docs.json index 856596678..704605353 100644 --- a/packages/react/docs.json +++ b/packages/react/docs.json @@ -366,6 +366,226 @@ "description": "Theme aware style object." } ], + "Container": [ + { + "name": "css", + "type": "CSS", + "required": false, + "description": "Theme aware style object" + }, + { + "name": "fixed", + "type": "boolean", + "defaultValue": "true", + "required": false, + "description": "Whether the container should adjust its max-width based on the current screen size." + }, + { + "name": "maxWidth", + "type": "\"small\" | \"medium\" | \"large\" | \"x-large\" | \"x-small\"", + "defaultValue": "'large'", + "required": false, + "description": "The max-width of the container." + } + ], + "DataTable": [ + { + "name": "css", + "type": "CSS", + "required": false, + "description": "Theme aware style object" + }, + { + "name": "data", + "type": "TData[]", + "required": true, + "description": "The data used to populate the table." + }, + { + "name": "defaultColumn", + "type": "Partial>", + "required": false, + "description": "A default ColumnDef applied to all components in the table." + }, + { + "name": "columns", + "type": "ColumnDef[]", + "required": true, + "description": "The column definition for the table.\n\nShould follow the `@tanstack/react-table` [ColumnDef](https://tanstack.com/table/v8/docs/guide/column-defs)" + }, + { + "name": "initialState", + "type": "Partial", + "required": false, + "description": "The initial state of the table, can be set without controlling the state completely." + }, + { + "name": "isLoading", + "type": "boolean", + "required": false, + "description": "Whether the table is currently loading data." + }, + { + "name": "enableExpandAll", + "type": "boolean", + "defaultValue": "false", + "required": false, + "description": "Whether the table supports expanding all table rows." + }, + { + "name": "enableExpanding", + "type": "boolean", + "defaultValue": "true", + "required": false, + "description": "Whether the table supports row expansion." + }, + { + "name": "enablePagination", + "type": "boolean", + "defaultValue": "true", + "required": false, + "description": "Whether the table supports pagination." + }, + { + "name": "enablePinning", + "type": "boolean", + "defaultValue": "true", + "required": false, + "description": "Whether the table supports pinned columns." + }, + { + "name": "enableMultiRowSelection", + "type": "boolean | ((row: Row) => boolean)", + "defaultValue": "true", + "required": false, + "description": "Whether to enable multiple row selection for all rows in the table.\n\nOptionally pass in a function that given a row, returns whether to enable/disable row selection for the children in that row" + }, + { + "name": "enableRowSelection", + "type": "boolean | ((row: Row) => boolean)", + "defaultValue": "false", + "required": false, + "description": "Whether to enable row selection for all rows in the table.\n\nOptionally pass in a function that given a row, returns whether to enable/disable row selection for that row" + }, + { + "name": "enableSelectAll", + "type": "boolean", + "defaultValue": "true", + "required": false, + "description": "Whether the table supports selecting all table rows." + }, + { + "name": "enableSorting", + "type": "boolean", + "defaultValue": "true", + "required": false, + "description": "Whether sorting is enabled for the table." + }, + { + "name": "enableSortingRemoval", + "type": "boolean", + "defaultValue": "true", + "required": false, + "description": "Whether the sort can removed from columns" + }, + { + "name": "enableStickyHeader", + "type": "boolean", + "defaultValue": "false", + "required": false, + "description": "Whether the table header should stick when scrolling vertically" + }, + { + "name": "expandAllButtonProps", + "type": "IconButtonProps | ((props: { table: DataTable; }) => IconButtonProps)", + "required": false, + "description": "Props passed to the expand all button component" + }, + { + "name": "expandButtonProps", + "type": "IconButtonProps | ((props: { table: DataTable; row: Row; }) => IconButtonProps)", + "required": false, + "description": "Props passed to the expand button component" + }, + { + "name": "manualExpanding", + "type": "boolean", + "required": false, + "description": "Whether the expanding state for the table is controlled." + }, + { + "name": "manualPagination", + "type": "boolean", + "required": false, + "description": "Whether the pagination state for the table is controlled." + }, + { + "name": "manualSorting", + "type": "boolean", + "required": false, + "description": "Whether the sorting state for the table is controlled." + }, + { + "name": "pageCount", + "type": "number", + "required": false, + "description": "A total pageCount of the table (controlled)." + }, + { + "name": "paginationProps", + "type": "(props: { table: DataTable; }) => Partial>", + "required": false, + "description": "Props passed to the pagination component" + }, + { + "name": "rowCount", + "type": "number", + "required": false, + "description": "The total number of rows for the total table (controlled).\n\nUsed to display the total count in the table pagination" + }, + { + "name": "selectCheckboxProps", + "type": "CheckboxProps<\"label\"> | ((props: { table: DataTable; row: Row; }) => CheckboxProps<\"label\">)", + "required": false, + "description": "Props passed to the select checkbox" + }, + { + "name": "selectAllCheckboxProps", + "type": "CheckboxProps<\"label\"> | ((props: { table: DataTable; }) => CheckboxProps<\"label\">)", + "required": false, + "description": "Props passed to the select all checkbox" + }, + { + "name": "state", + "type": "Partial", + "required": false, + "description": "State object for the table (controlled)." + }, + { + "name": "onExpandedChange", + "type": "OnChangeFn", + "required": false, + "description": "Handler that is called on expanded change." + }, + { + "name": "onPaginationChange", + "type": "OnChangeFn", + "required": false, + "description": "Handler that is called on pagination change." + }, + { + "name": "onRowSelectionChange", + "type": "OnChangeFn", + "required": false, + "description": "Handler that is called on row selection change." + }, + { + "name": "onSortingChange", + "type": "OnChangeFn", + "required": false, + "description": "Handler that is called on sort change." + } + ], "DatePicker": [ { "name": "children", @@ -1426,6 +1646,13 @@ "required": false, "description": "Theme aware style object" }, + { + "name": "getPaginationLabel", + "type": "({ count, from, to, }: { count: number; from: number; to: number; }) => ReactNode", + "defaultValue": "`${from}-${to} of ${totalRowCount}`", + "required": false, + "description": "Generate a localized label for the rows per page label (localization)." + }, { "name": "getItemAriaLabel", "type": "(type: \"next\" | \"previous\" | \"page\", page?: number | undefined, isActive?: boolean | undefined) => string", @@ -1459,6 +1686,13 @@ "required": false, "description": "The number of rows rendered per page." }, + { + "name": "showLabel", + "type": "boolean", + "defaultValue": "false", + "required": false, + "description": "Whether to show the pagination label." + }, { "name": "showPageNumbers", "type": "boolean", diff --git a/packages/react/package.json b/packages/react/package.json index a116a546f..e2f9a9d68 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -85,6 +85,7 @@ "@react-stately/tooltip": "^3.2.2", "@react-stately/tree": "^3.4.1", "@react-stately/utils": "^3.6.0", + "@tanstack/react-table": "^8.8.5", "clsx": "^1.2.1", "lodash.isobject": "^3.0.2", "react-content-loader": "^6.2.1", diff --git a/packages/react/src/components/DataTable/DataTable.context.ts b/packages/react/src/components/DataTable/DataTable.context.ts new file mode 100644 index 000000000..b3044aecd --- /dev/null +++ b/packages/react/src/components/DataTable/DataTable.context.ts @@ -0,0 +1,14 @@ +import { RowData, Table } from '@tanstack/react-table'; +import { createContext } from '../../utils'; + +export interface DataTableContext { + options: { + enableStickyHeader?: boolean; + }; + rowCount?: number; + table: Table; +} + +export const [DataTableProvider, useDataTable] = createContext({ + name: 'DataTableContext', +}); diff --git a/packages/react/src/components/DataTable/DataTable.styles.ts b/packages/react/src/components/DataTable/DataTable.styles.ts new file mode 100644 index 000000000..ed567dbcf --- /dev/null +++ b/packages/react/src/components/DataTable/DataTable.styles.ts @@ -0,0 +1,119 @@ +import { pxToRem, styled } from '@project44-manifest/react-styles'; + +export const StyledDataTable = styled('div', { + $$tableBackgroundColor: '$colors$background-primary', + + backgroundColor: '$$tableBackgroundColor', + boxSizing: 'border-box', + color: '$text-primary', + border: '1px solid $border-primary', + borderRadius: '$small', + + '.manifest-data-table__container': { + maxWidth: '100%', + overflow: 'auto', + width: '100%', + + '&--sticky-header': { + maxHeight: 'clamp(350px, calc(100vh - 0px), 9999px)', + }, + + '&--sticky-header, &--pagination': { + maxHeight: 'clamp(350px, calc(100vh - 48px), 9999px)', + }, + + '.manifest-table tr:hover td': { + backgroundColor: '$background-secondary', + }, + }, + + '.manifest-data-table__checkbox': { + alignItems: 'center', + display: 'flex', + }, + + '.manifest-data-table__footer': { + alignItems: 'center', + borderTop: '1px solid $border-primary', + display: 'flex', + justifyContent: 'space-between', + minHeight: pxToRem(48), + px: pxToRem(12), + + '> .manifest-pagination': { + width: '100%', + }, + }, + + '.manifest-table': { + borderCollapse: 'separate', + borderSpacing: 0, + display: 'table', + width: '100%', + + '&__cell': { + borderBottom: '1px solid $border-primary', + display: 'table-cell', + fontSize: '$small', + fontWeight: '$regular', + lineHeight: '$small', + padding: `${pxToRem(6)} ${pxToRem(12)}`, + textAlign: 'left', + verticalAlign: 'inherit', + + '&--pinned': { + backgroundColor: '$$tableBackgroundColor', + position: 'sticky', + zIndex: 1, + }, + }, + + '&__cell--header': { + fontSize: '$x-small', + fontWeight: '$semibold', + lineHeight: '$x-small', + + '&.manifest-table__cell--pinned': { + zIndex: 2, + }, + }, + + '&__cell--sticky-header': { + backgroundColor: '$$tableBackgroundColor', + position: 'sticky', + top: 0, + zIndex: 1, + }, + + '&__header': { + display: 'table-row-group', + }, + + '&__row': { + color: 'inherit', + display: 'table-row', + verticalAlign: 'middle', + outline: 0, + }, + }, + + '.manifest-table__heading': { + appearance: 'none', + alignItems: 'center', + background: 'none', + border: 'none', + borderRadius: '$small', + color: 'inherit', + cursor: 'pointer', + display: 'inline-flex', + fontSize: 'inherit', + gap: '$small', + lineHeight: 'inherit', + mx: '-$x-small', + padding: `$x-small ${pxToRem(6)}`, + + '&:hover': { + backgroundColor: '$background-secondary', + }, + }, +}); diff --git a/packages/react/src/components/DataTable/DataTable.tsx b/packages/react/src/components/DataTable/DataTable.tsx new file mode 100644 index 000000000..8d9ca09b4 --- /dev/null +++ b/packages/react/src/components/DataTable/DataTable.tsx @@ -0,0 +1,160 @@ +import * as React from 'react'; +import { cx } from '@project44-manifest/react-styles'; +import { + ColumnDef, + getCoreRowModel, + getExpandedRowModel, + getPaginationRowModel, + getSortedRowModel, + Row, + RowData, + TableOptions, + useReactTable, +} from '@tanstack/react-table'; +import { + DataTableBody, + DataTableCheckbox, + DataTableExpandAllButton, + DataTableExpandButton, + DataTableHeader, + DataTablePagination, +} from './components'; +import { StyledDataTable } from './DataTable.styles'; +import type { DataTable, DataTableProps } from './DataTable.types'; + +export function DataTable(props: DataTableProps) { + const { + data: dataProp, + defaultColumn = { + minSize: 40, + maxSize: 1000, + size: 180, + }, + columns: columnsProp, + enableExpandAll = true, + enableExpanding = false, + enableMultiRowSelection = true, + enablePagination = true, + enablePinning = false, + enableRowSelection = false, + enableSelectAll = true, + enableSorting = true, + enableStickyHeader = false, + expandAllButtonProps = {}, + expandButtonProps = {}, + initialState, + isLoading, + manualExpanding, + manualPagination: manualPaginationProp, + manualSorting, + pageCount, + paginationProps = {}, + selectAllCheckboxProps = {}, + selectCheckboxProps = {}, + rowCount, + state, + onExpandedChange, + onPaginationChange, + onRowSelectionChange, + onSortingChange, + ...other + } = props; + + let manualPagination = manualPaginationProp; + + if (!enablePagination && manualPagination === undefined) { + manualPagination = true; + } + + const columns = React.useMemo[]>( + () => + [ + enableExpanding && { + id: 'manifest-data-table-row-expand', + // eslint-disable-next-line react/no-unstable-nested-components + header: ({ table }: { table: DataTable }) => + enableExpandAll && , + // eslint-disable-next-line react/no-unstable-nested-components + cell: ({ row, table }: { row: Row; table: DataTable }) => ( + + ), + size: 40, + }, + enableRowSelection && { + id: 'manifest-data-table-row-select', + // eslint-disable-next-line react/no-unstable-nested-components + header: ({ table }: { table: DataTable }) => + enableSelectAll && , + // eslint-disable-next-line react/no-unstable-nested-components + cell: ({ row, table }: { row: Row; table: DataTable }) => ( + + ), + size: 40, + }, + ...columnsProp, + ].filter(Boolean) as ColumnDef[], + [columnsProp, enableExpandAll, enableExpanding, enableRowSelection, enableSelectAll], + ); + + const data: TData[] = React.useMemo( + () => + isLoading && !dataProp.length + ? ([ + ...Array.from({ + length: state?.pagination?.pageSize || initialState?.pagination?.pageSize || 10, + }).fill(null), + ] as TData[]) + : dataProp, + [dataProp, initialState?.pagination?.pageSize, state?.pagination?.pageSize, isLoading], + ); + + const table = useReactTable({ + columns, + data, + defaultColumn, + enableExpandAll, + enableExpanding, + enablePinning, + enableMultiRowSelection, + enableRowSelection, + enableSelectAll, + enableSorting, + enableStickyHeader, + expandAllButtonProps, + expandButtonProps, + getCoreRowModel: getCoreRowModel(), + getExpandedRowModel: getExpandedRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getSubRows: (row: Row) => row?.subRows as TData[], + initialState, + isLoading, + manualExpanding, + manualPagination, + manualSorting, + paginationProps, + rowCount, + selectAllCheckboxProps, + selectCheckboxProps, + state, + ...(manualExpanding && { onExpandedChange }), + ...(manualPagination && { onPaginationChange }), + ...(manualSorting && { onSortingChange }), + } as TableOptions) as DataTable; + + return ( + +
+ + + +
+
+ +
+ ); +} diff --git a/packages/react/src/components/DataTable/DataTable.types.ts b/packages/react/src/components/DataTable/DataTable.types.ts new file mode 100644 index 000000000..eae110068 --- /dev/null +++ b/packages/react/src/components/DataTable/DataTable.types.ts @@ -0,0 +1,210 @@ +import type { CSS } from '@project44-manifest/react-styles'; +import type { + ColumnDef, + ColumnPinningState, + ExpandedState, + OnChangeFn, + PaginationState, + Row, + RowData, + RowSelectionState, + SortingState, + Table, +} from '@tanstack/react-table'; +import type { IconButtonProps } from '../button'; +import type { CheckboxProps } from '../Checkbox'; +import type { PaginationProps } from '../Pagination'; + +export { ColumnDef }; + +export interface DataTableState { + /** + * The state for pinned columns. + */ + columnPinning: ColumnPinningState; + /** + * The state for expanded table rows. + */ + expanded: ExpandedState; + /** + * The pagination state for the table. + */ + pagination: PaginationState; + /** + * The row selection state for the table. + */ + rowSelection: RowSelectionState; + /** + * The sorting state for the table. + */ + sorting: SortingState; +} + +export interface DataTable extends Omit, 'options'> { + options: DataTableProps; +} + +export interface DataTableProps { + /** + * Theme aware style object + */ + css?: CSS; + /** + * The data used to populate the table. + */ + data: TData[]; + /** + * A default ColumnDef applied to all components in the table. + */ + defaultColumn?: Partial>; + /** + * The column definition for the table. + * + * Should follow the `@tanstack/react-table` [ColumnDef](https://tanstack.com/table/v8/docs/guide/column-defs) + */ + columns: ColumnDef[]; + /** + * The initial state of the table, can be set without controlling the state completely. + */ + initialState?: Partial; + /** + * Whether the table is currently loading data. + */ + isLoading?: boolean; + /** + * Whether the table supports expanding all table rows. + * + * @default false + */ + enableExpandAll?: boolean; + /** + * Whether the table supports row expansion. + * + * @default true + */ + enableExpanding?: boolean; + /** + * Whether the table supports pagination. + * + * @default true + */ + enablePagination?: boolean; + /** + * Whether the table supports pinned columns. + * + * @default true + */ + enablePinning?: boolean; + /** + * Whether to enable multiple row selection for all rows in the table. + * + * Optionally pass in a function that given a row, returns whether to enable/disable row selection for the children in that row + * + * @default true + */ + enableMultiRowSelection?: boolean | ((row: Row) => boolean); + /** + * Whether to enable row selection for all rows in the table. + * + * Optionally pass in a function that given a row, returns whether to enable/disable row selection for that row + * + * @default false + */ + enableRowSelection?: boolean | ((row: Row) => boolean); + /** + * Whether the table supports selecting all table rows. + * + * @default true + */ + enableSelectAll?: boolean; + /** + * Whether sorting is enabled for the table. + * + * @default true + */ + enableSorting?: boolean; + /** + * Whether the sort can removed from columns + * + * @default true + */ + enableSortingRemoval?: boolean; + /** + * Whether the table header should stick when scrolling vertically + * + * @default false + */ + enableStickyHeader?: boolean; + /** + * Props passed to the expand all button component + */ + expandAllButtonProps?: + | IconButtonProps + | ((props: { table: DataTable }) => IconButtonProps); + /** + * Props passed to the expand button component + */ + expandButtonProps?: + | IconButtonProps + | ((props: { table: DataTable; row: Row }) => IconButtonProps); + /** + * Whether the expanding state for the table is controlled. + */ + manualExpanding?: boolean; + /** + * Whether the pagination state for the table is controlled. + */ + manualPagination?: boolean; + /** + * Whether the sorting state for the table is controlled. + */ + manualSorting?: boolean; + /** + * A total pageCount of the table (controlled). + */ + pageCount?: number; + /** + * Props passed to the pagination component + */ + paginationProps?: (props: { + table: DataTable; + }) => + | Partial> + | Partial>; + /** + * The total number of rows for the total table (controlled). + * + * Used to display the total count in the table pagination + */ + rowCount?: number; + /** + * Props passed to the select checkbox + */ + selectCheckboxProps?: + | CheckboxProps + | ((props: { table: DataTable; row: Row }) => CheckboxProps); + /** + * Props passed to the select all checkbox + */ + selectAllCheckboxProps?: CheckboxProps | ((props: { table: DataTable }) => CheckboxProps); + /** + * State object for the table (controlled). + */ + state?: Partial; + /** + * Handler that is called on expanded change. + */ + onExpandedChange?: OnChangeFn; + /** + * Handler that is called on pagination change. + */ + onPaginationChange?: OnChangeFn; + /** + * Handler that is called on row selection change. + */ + onRowSelectionChange?: OnChangeFn; + /** + * Handler that is called on sort change. + */ + onSortingChange?: OnChangeFn; +} diff --git a/packages/react/src/components/DataTable/components/DataTableBody/DataTableBody.tsx b/packages/react/src/components/DataTable/components/DataTableBody/DataTableBody.tsx new file mode 100644 index 000000000..dbc3c0e5e --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableBody/DataTableBody.tsx @@ -0,0 +1,19 @@ +import { RowData } from '@tanstack/react-table'; +import { DataTableCell } from '../DataTableCell'; +import type { DataTableBodyProps } from './DataTableBody.types'; + +export function DataTableBody(props: DataTableBodyProps) { + const { table } = props; + + return ( + + {table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + ))} + + ))} + + ); +} diff --git a/packages/react/src/components/DataTable/components/DataTableBody/DataTableBody.types.ts b/packages/react/src/components/DataTable/components/DataTableBody/DataTableBody.types.ts new file mode 100644 index 000000000..150f674c0 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableBody/DataTableBody.types.ts @@ -0,0 +1,6 @@ +import { RowData } from '@tanstack/react-table'; +import type { DataTable } from '../../DataTable.types'; + +export interface DataTableBodyProps { + table: DataTable; +} diff --git a/packages/react/src/components/DataTable/components/DataTableBody/index.ts b/packages/react/src/components/DataTable/components/DataTableBody/index.ts new file mode 100644 index 000000000..605034c46 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableBody/index.ts @@ -0,0 +1 @@ +export * from './DataTableBody'; diff --git a/packages/react/src/components/DataTable/components/DataTableCell/DataTableCell.tsx b/packages/react/src/components/DataTable/components/DataTableCell/DataTableCell.tsx new file mode 100644 index 000000000..6d5bfa886 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableCell/DataTableCell.tsx @@ -0,0 +1,33 @@ +import * as React from 'react'; +import { cx } from '@project44-manifest/react-styles'; +import { flexRender, RowData } from '@tanstack/react-table'; +import { Skeleton } from '../../../Skeleton'; +import { getColumnLayoutStyles } from '../../utils'; +import { DataTableCellProps } from './DataTableCell.types'; + +export function DataTableCell( + props: DataTableCellProps, +) { + const { cell, table } = props; + + const styles: React.CSSProperties = getColumnLayoutStyles(table, cell.column); + const isNested = cell.column.id === 'manifest-data-table-row-expand'; + + return ( + + {table.options.isLoading && ( +
+ + + +
+ )} + {!table.options.isLoading && flexRender(cell.column.columnDef.cell, cell.getContext())} + + ); +} diff --git a/packages/react/src/components/DataTable/components/DataTableCell/DataTableCell.types.ts b/packages/react/src/components/DataTable/components/DataTableCell/DataTableCell.types.ts new file mode 100644 index 000000000..3f678a8cc --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableCell/DataTableCell.types.ts @@ -0,0 +1,7 @@ +import { Cell, RowData } from '@tanstack/react-table'; +import type { DataTable } from '../../DataTable.types'; + +export interface DataTableCellProps { + cell: Cell; + table: DataTable; +} diff --git a/packages/react/src/components/DataTable/components/DataTableCell/index.ts b/packages/react/src/components/DataTable/components/DataTableCell/index.ts new file mode 100644 index 000000000..8d9a5b4c3 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableCell/index.ts @@ -0,0 +1 @@ +export * from './DataTableCell'; diff --git a/packages/react/src/components/DataTable/components/DataTableCheckbox/DataTableCheckbox.tsx b/packages/react/src/components/DataTable/components/DataTableCheckbox/DataTableCheckbox.tsx new file mode 100644 index 000000000..544afc68e --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableCheckbox/DataTableCheckbox.tsx @@ -0,0 +1,49 @@ +import * as React from 'react'; +import { RowData } from '@tanstack/react-table'; +import { Checkbox } from '../../../Checkbox'; +import type { DataTableCheckboxProps } from './DataTableCheckbox.types'; + +export function DataTableCheckbox(props: DataTableCheckboxProps) { + const { row, table } = props; + + const { options } = table; + const { selectCheckboxProps, selectAllCheckboxProps } = options; + + let parsedProps; + + if (row) { + parsedProps = + typeof selectCheckboxProps === 'function' + ? selectCheckboxProps({ row, table }) + : selectCheckboxProps; + } else { + parsedProps = + typeof selectAllCheckboxProps === 'function' + ? selectAllCheckboxProps({ table }) + : selectAllCheckboxProps; + } + + const isSelected = row ? row?.getIsSelected() : table.getIsAllPageRowsSelected(); + const isDisabled = row && !row.getCanSelect(); + const isIndeterminate = row + ? row?.getIsSomeSelected() + : table.getIsSomeRowsSelected() && !table.getIsAllPageRowsSelected(); + + const handleChange = React.useCallback( + (checked: boolean) => + row ? void row?.toggleSelected(checked) : void table.toggleAllPageRowsSelected(), + [row, table], + ); + + return ( +
+ +
+ ); +} diff --git a/packages/react/src/components/DataTable/components/DataTableCheckbox/DataTableCheckbox.types.ts b/packages/react/src/components/DataTable/components/DataTableCheckbox/DataTableCheckbox.types.ts new file mode 100644 index 000000000..52bf891af --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableCheckbox/DataTableCheckbox.types.ts @@ -0,0 +1,7 @@ +import { Row, RowData } from '@tanstack/react-table'; +import type { DataTable } from '../../DataTable.types'; + +export interface DataTableCheckboxProps { + row?: Row; + table: DataTable; +} diff --git a/packages/react/src/components/DataTable/components/DataTableCheckbox/index.ts b/packages/react/src/components/DataTable/components/DataTableCheckbox/index.ts new file mode 100644 index 000000000..cf07252a1 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableCheckbox/index.ts @@ -0,0 +1 @@ +export * from './DataTableCheckbox'; diff --git a/packages/react/src/components/DataTable/components/DataTableColumn/DataTableColumn.tsx b/packages/react/src/components/DataTable/components/DataTableColumn/DataTableColumn.tsx new file mode 100644 index 000000000..c1a5649e6 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableColumn/DataTableColumn.tsx @@ -0,0 +1,45 @@ +import * as React from 'react'; +import { ArrowDown, ArrowUp, Sort } from '@project44-manifest/react-icons'; +import { cx } from '@project44-manifest/react-styles'; +import { flexRender, RowData } from '@tanstack/react-table'; +import { getColumnLayoutStyles } from '../../utils'; +import { DataTableColumnProps } from './DataTableColumn.types'; + +export function DataTableColumn( + props: DataTableColumnProps, +) { + const { header, table } = props; + const { column } = header; + + const isSortable = column.getCanSort(); + + const styles: React.CSSProperties = getColumnLayoutStyles(table, column); + + return ( + + {isSortable ? ( + + ) : ( + flexRender(header.column.columnDef.header, header.getContext()) + )} + + ); +} diff --git a/packages/react/src/components/DataTable/components/DataTableColumn/DataTableColumn.types.ts b/packages/react/src/components/DataTable/components/DataTableColumn/DataTableColumn.types.ts new file mode 100644 index 000000000..8fead5c9d --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableColumn/DataTableColumn.types.ts @@ -0,0 +1,7 @@ +import { Header, RowData } from '@tanstack/react-table'; +import type { DataTable } from '../../DataTable.types'; + +export interface DataTableColumnProps { + header: Header; + table: DataTable; +} diff --git a/packages/react/src/components/DataTable/components/DataTableColumn/index.ts b/packages/react/src/components/DataTable/components/DataTableColumn/index.ts new file mode 100644 index 000000000..ba6a4ed18 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableColumn/index.ts @@ -0,0 +1 @@ +export * from './DataTableColumn'; diff --git a/packages/react/src/components/DataTable/components/DataTableExpandAllButton/DataTableExpandAllButton.tsx b/packages/react/src/components/DataTable/components/DataTableExpandAllButton/DataTableExpandAllButton.tsx new file mode 100644 index 000000000..99485c2be --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableExpandAllButton/DataTableExpandAllButton.tsx @@ -0,0 +1,48 @@ +import * as React from 'react'; +import type { PressEvent } from '@react-types/shared'; +import { ChevronDown } from '@project44-manifest/react-icons'; +import { RowData } from '@tanstack/react-table'; +import { IconButton } from '../../../button'; +import type { DataTableExpandAllButtonProps } from './DataTableExpandAllButton.types'; + +export function DataTableExpandAllButton( + props: DataTableExpandAllButtonProps, +) { + const { table } = props; + + const { options } = table; + const { expandAllButtonProps, isLoading } = options; + + const parsedProps = + typeof expandAllButtonProps === 'function' + ? expandAllButtonProps({ table }) + : expandAllButtonProps; + + const isAllRowsExpanded = table.getIsAllRowsExpanded(); + + const handleToggleExpand = React.useCallback( + (event: PressEvent) => { + void table.toggleAllRowsExpanded(!isAllRowsExpanded); + + parsedProps?.onPress?.(event); + }, + [isAllRowsExpanded, parsedProps, table], + ); + + return ( + + + + ); +} diff --git a/packages/react/src/components/DataTable/components/DataTableExpandAllButton/DataTableExpandAllButton.types.ts b/packages/react/src/components/DataTable/components/DataTableExpandAllButton/DataTableExpandAllButton.types.ts new file mode 100644 index 000000000..a32697cd1 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableExpandAllButton/DataTableExpandAllButton.types.ts @@ -0,0 +1,6 @@ +import { RowData } from '@tanstack/react-table'; +import type { DataTable } from '../../DataTable.types'; + +export interface DataTableExpandAllButtonProps { + table: DataTable; +} diff --git a/packages/react/src/components/DataTable/components/DataTableExpandAllButton/index.ts b/packages/react/src/components/DataTable/components/DataTableExpandAllButton/index.ts new file mode 100644 index 000000000..488ee6e64 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableExpandAllButton/index.ts @@ -0,0 +1 @@ +export * from './DataTableExpandAllButton'; diff --git a/packages/react/src/components/DataTable/components/DataTableExpandButton/DataTableExpandButton.tsx b/packages/react/src/components/DataTable/components/DataTableExpandButton/DataTableExpandButton.tsx new file mode 100644 index 000000000..6f7135374 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableExpandButton/DataTableExpandButton.tsx @@ -0,0 +1,47 @@ +import * as React from 'react'; +import type { PressEvent } from '@react-types/shared'; +import { ChevronDown } from '@project44-manifest/react-icons'; +import { RowData } from '@tanstack/react-table'; +import { IconButton } from '../../../..'; +import type { DataTableExpandButtonProps } from './DataTableExpandButton.types'; + +export function DataTableExpandButton( + props: DataTableExpandButtonProps, +) { + const { row, table } = props; + + const { options } = table; + const { expandButtonProps, isLoading } = options; + + const parsedProps = + typeof expandButtonProps === 'function' ? expandButtonProps({ table, row }) : expandButtonProps; + + const canExpand = row.getCanExpand(); + const isExpanded = row.getIsExpanded(); + + const handleToggleExpand = React.useCallback( + (event: PressEvent) => { + void row.toggleExpanded(); + + parsedProps?.onPress?.(event); + }, + [row, parsedProps], + ); + + return ( + + + + ); +} diff --git a/packages/react/src/components/DataTable/components/DataTableExpandButton/DataTableExpandButton.types.ts b/packages/react/src/components/DataTable/components/DataTableExpandButton/DataTableExpandButton.types.ts new file mode 100644 index 000000000..5349c76cf --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableExpandButton/DataTableExpandButton.types.ts @@ -0,0 +1,7 @@ +import { Row, RowData } from '@tanstack/react-table'; +import type { DataTable } from '../../DataTable.types'; + +export interface DataTableExpandButtonProps { + row: Row; + table: DataTable; +} diff --git a/packages/react/src/components/DataTable/components/DataTableExpandButton/index.ts b/packages/react/src/components/DataTable/components/DataTableExpandButton/index.ts new file mode 100644 index 000000000..021d45402 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableExpandButton/index.ts @@ -0,0 +1 @@ +export * from './DataTableExpandButton'; diff --git a/packages/react/src/components/DataTable/components/DataTableHeader/DataTableHeader.tsx b/packages/react/src/components/DataTable/components/DataTableHeader/DataTableHeader.tsx new file mode 100644 index 000000000..e81f0a4a4 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableHeader/DataTableHeader.tsx @@ -0,0 +1,24 @@ +import { cx } from '@project44-manifest/react-styles'; +import { RowData } from '@tanstack/react-table'; +import { DataTableColumn } from '../DataTableColumn'; +import type { DataTableHeaderProps } from './DataTableHeader.types'; + +export function DataTableHeader(props: DataTableHeaderProps) { + const { table } = props; + + return ( + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + ))} + + ))} + + ); +} diff --git a/packages/react/src/components/DataTable/components/DataTableHeader/DataTableHeader.types.ts b/packages/react/src/components/DataTable/components/DataTableHeader/DataTableHeader.types.ts new file mode 100644 index 000000000..f0591b628 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableHeader/DataTableHeader.types.ts @@ -0,0 +1,7 @@ +import { RowData } from '@tanstack/react-table'; +import type { DataTable } from '../../DataTable.types'; + +export interface DataTableHeaderProps { + enableStickyHeader?: boolean; + table: DataTable; +} diff --git a/packages/react/src/components/DataTable/components/DataTableHeader/index.ts b/packages/react/src/components/DataTable/components/DataTableHeader/index.ts new file mode 100644 index 000000000..1af9fc7cd --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTableHeader/index.ts @@ -0,0 +1 @@ +export * from './DataTableHeader'; diff --git a/packages/react/src/components/DataTable/components/DataTablePagination/DataTablePagination.tsx b/packages/react/src/components/DataTable/components/DataTablePagination/DataTablePagination.tsx new file mode 100644 index 000000000..4afaf3578 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTablePagination/DataTablePagination.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import { RowData } from '@tanstack/react-table'; +import { Pagination } from '../../../Pagination'; +import type { DataTablePaginationProps } from './DataTablePagination.types'; + +export function DataTablePagination(props: DataTablePaginationProps) { + const { rowCount, table } = props; + + const { options, getPrePaginationRowModel, getState, setPageIndex } = table; + const { paginationProps } = options; + const { + pagination: { pageSize = 10, pageIndex = 0 }, + } = getState(); + + const parsedProps = + typeof paginationProps === 'function' ? paginationProps({ table }) : paginationProps; + + const totalRowCount = rowCount ?? getPrePaginationRowModel().rows.length; + + const handlePageChange = React.useCallback( + (page: number) => void setPageIndex(page - 1), + [setPageIndex], + ); + + return ( +
+ +
+ ); +} diff --git a/packages/react/src/components/DataTable/components/DataTablePagination/DataTablePagination.types.ts b/packages/react/src/components/DataTable/components/DataTablePagination/DataTablePagination.types.ts new file mode 100644 index 000000000..5c8952d39 --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTablePagination/DataTablePagination.types.ts @@ -0,0 +1,8 @@ +import { RowData } from '@tanstack/react-table'; +import { PaginationProps } from '../../../Pagination'; +import type { DataTable } from '../../DataTable.types'; + +export interface DataTablePaginationProps extends PaginationProps { + rowCount?: number; + table: DataTable; +} diff --git a/packages/react/src/components/DataTable/components/DataTablePagination/index.ts b/packages/react/src/components/DataTable/components/DataTablePagination/index.ts new file mode 100644 index 000000000..374ba7bfc --- /dev/null +++ b/packages/react/src/components/DataTable/components/DataTablePagination/index.ts @@ -0,0 +1 @@ +export * from './DataTablePagination'; diff --git a/packages/react/src/components/DataTable/components/index.ts b/packages/react/src/components/DataTable/components/index.ts new file mode 100644 index 000000000..5403ea560 --- /dev/null +++ b/packages/react/src/components/DataTable/components/index.ts @@ -0,0 +1,6 @@ +export * from './DataTableBody'; +export * from './DataTableCheckbox'; +export * from './DataTableExpandAllButton'; +export * from './DataTableExpandButton'; +export * from './DataTableHeader'; +export * from './DataTablePagination'; diff --git a/packages/react/src/components/DataTable/index.ts b/packages/react/src/components/DataTable/index.ts new file mode 100644 index 000000000..89209122e --- /dev/null +++ b/packages/react/src/components/DataTable/index.ts @@ -0,0 +1,2 @@ +export * from './DataTable'; +export type { ColumnDef, DataTableProps } from './DataTable.types'; diff --git a/packages/react/src/components/DataTable/utils/columns.ts b/packages/react/src/components/DataTable/utils/columns.ts new file mode 100644 index 000000000..0965d9863 --- /dev/null +++ b/packages/react/src/components/DataTable/utils/columns.ts @@ -0,0 +1,28 @@ +import type * as React from 'react'; +import { theme } from '@project44-manifest/react-styles'; +import type { Column, RowData } from '@tanstack/react-table'; +import type { DataTable } from '../DataTable.types'; + +export const getColumnLayoutStyles = ( + table: DataTable, + column: Column, +) => { + const leftOffset = column.getStart('left'); + const rightOffset = (table.getRightLeafHeaders().length - 1 - column.getPinnedIndex()) * 180; + const isFirstRightPinnedColumn = + column.getIsPinned() === 'right' && column.getPinnedIndex() === 0; + const isLastLeftPinnedColumn = + column.getIsPinned() === 'left' && + table.getLeftLeafHeaders().length - 1 === column.getPinnedIndex(); + + const styles: React.CSSProperties = { + left: column.getIsPinned() === 'left' ? `${leftOffset}px` : undefined, + right: column.getIsPinned() === 'right' ? `${rightOffset}px` : undefined, + minWidth: `max(calc(${column.getSize()} * 1px), ${column.columnDef.minSize ?? 40}px)`, + width: `calc(${column.getSize()} * 1px)`, + ...(isFirstRightPinnedColumn && { borderLeft: `1px solid ${theme.colors['border-primary']}` }), + ...(isLastLeftPinnedColumn && { borderRight: `1px solid ${theme.colors['border-primary']}` }), + }; + + return styles; +}; diff --git a/packages/react/src/components/DataTable/utils/index.ts b/packages/react/src/components/DataTable/utils/index.ts new file mode 100644 index 000000000..a7f066b20 --- /dev/null +++ b/packages/react/src/components/DataTable/utils/index.ts @@ -0,0 +1 @@ +export * from './columns'; diff --git a/packages/react/src/components/Pagination/Pagination.styles.ts b/packages/react/src/components/Pagination/Pagination.styles.ts index 439d143cd..22680f6f2 100644 --- a/packages/react/src/components/Pagination/Pagination.styles.ts +++ b/packages/react/src/components/Pagination/Pagination.styles.ts @@ -2,11 +2,17 @@ import { pxToRem, styled } from '@project44-manifest/react-styles'; export const StyledPagination = styled('div', { alignItems: 'center', - boxSizing: 'border-box', - columnGap: '$x-small', display: 'flex', - flexWrap: 'wrap', - rowGap: '$small', + justifyContent: 'space-between', + + '.manifest-pagination__actions': { + alignItems: 'center', + boxSizing: 'border-box', + columnGap: '$x-small', + display: 'flex', + flexWrap: 'wrap', + rowGap: '$small', + }, '.manifest-pagination__ellipsis': { backgroundColor: '$palette-grey-50', diff --git a/packages/react/src/components/Pagination/Pagination.tsx b/packages/react/src/components/Pagination/Pagination.tsx index 62351da11..fa54d3e68 100644 --- a/packages/react/src/components/Pagination/Pagination.tsx +++ b/packages/react/src/components/Pagination/Pagination.tsx @@ -17,6 +17,9 @@ const range = (start: number, end: number) => { return Array.from({ length }, (_, i) => start + i); }; +const defaultPagiationLabel = ({ count, from, to }: { count: number; from: number; to: number }) => + `${from}-${to} of ${count}`; + function defaultGetItemAriaLabel( type: 'next' | 'page' | 'previous', page?: number, @@ -37,6 +40,7 @@ export const Pagination = React.forwardRef((props, forwardedRef) => { className: classNameProp, css, defaultPage = 1, + getPaginationLabel = defaultPagiationLabel, getItemAriaLabel = defaultGetItemAriaLabel, onChange = noop, nextLabel = 'Next', @@ -44,6 +48,7 @@ export const Pagination = React.forwardRef((props, forwardedRef) => { previousLabel = 'Previous', rowsPerPage = 10, siblings = 1, + showLabel = false, showPageNumbers = true, totalRowCount = 1, ...other @@ -103,44 +108,57 @@ export const Pagination = React.forwardRef((props, forwardedRef) => { return ( - - - {previousLabel} - - - {showPageNumbers && - pages.map((item, index) => ( - - {item === 'dots' && ( -
- ... -
- )} - {item !== 'dots' && ( - - {item.toString()} - - )} -
- ))} - - - {nextLabel} - - + {showLabel && ( +
+ + {getPaginationLabel({ + count: totalRowCount, + from: (page - 1) * rowsPerPage + 1, + to: Math.min(totalRowCount, rowsPerPage * page), + })} + +
+ )} +
+ + + {previousLabel} + + + {showPageNumbers && + pages.map((item, index) => ( + + {item === 'dots' && ( +
+ ... +
+ )} + {item !== 'dots' && ( + + {item.toString()} + + )} +
+ ))} + + + {nextLabel} + + +
); }) as ForwardRefComponent; diff --git a/packages/react/src/components/Pagination/Pagination.types.ts b/packages/react/src/components/Pagination/Pagination.types.ts index dac0d3ad0..66654d2da 100644 --- a/packages/react/src/components/Pagination/Pagination.types.ts +++ b/packages/react/src/components/Pagination/Pagination.types.ts @@ -19,6 +19,20 @@ export interface PaginationProps { * Theme aware style object */ css?: CSS; + /** + * Generate a localized label for the rows per page label (localization). + * + * @default `${from}-${to} of ${totalRowCount}` + */ + getPaginationLabel?: ({ + count, + from, + to, + }: { + count: number; + from: number; + to: number; + }) => React.ReactNode; /** * Generate screen reader friendly aria-labels for pagination items, used for internationalized strings. */ @@ -49,6 +63,12 @@ export interface PaginationProps { * @default 10 */ rowsPerPage?: number; + /** + * Whether to show the pagination label. + * + * @default false + */ + showLabel?: boolean; /** * Whether to show page numbers buttons. * diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 07e69dd75..1f4ac0c2f 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -25,7 +25,10 @@ export type { ComboboxItemProps } from './components/ComboboxItem'; export { ComboboxItem } from './components/ComboboxItem'; export type { ComboboxSectionProps } from './components/ComboboxSection'; export { ComboboxSection } from './components/ComboboxSection'; -export * from './components/container'; +export type { ContainerProps } from './components/container'; +export { Container } from './components/container'; +export type { ColumnDef, DataTableProps } from './components/DataTable'; +export { DataTable } from './components/DataTable'; export type { DatePickerProps } from './components/DatePicker'; export { DatePicker } from './components/DatePicker'; export type { DateRangePickerProps } from './components/DateRangePicker'; diff --git a/packages/react/stories/DataTable.stories.tsx b/packages/react/stories/DataTable.stories.tsx new file mode 100644 index 000000000..fbd880300 --- /dev/null +++ b/packages/react/stories/DataTable.stories.tsx @@ -0,0 +1,302 @@ +import { faker } from '@faker-js/faker'; +import { ColumnDef, DataTable } from '../src'; + +export default { + title: 'Components/DataTable', + component: DataTable, +}; + +export const Default = () => { + const data = [...Array.from({ length: 5 })].map(() => ({ + firstName: faker.name.firstName(), + lastName: faker.name.lastName(), + gender: faker.name.sex(), + age: faker.datatype.number(80), + address: faker.address.streetAddress(), + city: faker.address.city(), + state: faker.address.state(), + zipCode: faker.address.zipCode(), + })); + + const columns: ColumnDef<(typeof data)[0]>[] = [ + { + header: 'First Name', + accessorKey: 'firstName', + }, + { + header: 'Last Name', + accessorKey: 'lastName', + }, + { + header: 'gender', + accessorKey: 'gender', + }, + { + header: 'Age', + accessorKey: 'age', + }, + { + header: 'Address', + accessorKey: 'address', + }, + { + header: 'City', + accessorKey: 'city', + }, + { + header: 'State', + accessorKey: 'state', + }, + { + header: 'Zip', + accessorKey: 'zipCode', + }, + ]; + + return ; +}; + +export const StickyHeader = () => { + const data = [...Array.from({ length: 100 })].map(() => ({ + firstName: faker.name.firstName(), + lastName: faker.name.lastName(), + address: faker.address.streetAddress(), + state: faker.address.state(), + phoneNumber: faker.phone.number(), + })); + + const columns: ColumnDef<(typeof data)[0]>[] = [ + { + header: 'First Name', + accessorKey: 'firstName', + }, + { + header: 'Last Name', + accessorKey: 'lastName', + }, + { + header: 'Address', + accessorKey: 'address', + }, + { + header: 'State', + accessorKey: 'state', + }, + { + header: 'Phone Number', + accessorKey: 'phoneNumber', + }, + ]; + + return ( + + ); +}; + +export const StickyHeaderFixedTableHeight = () => { + const data = [...Array.from({ length: 100 })].map(() => ({ + firstName: faker.name.firstName(), + lastName: faker.name.lastName(), + address: faker.address.streetAddress(), + state: faker.address.state(), + phoneNumber: faker.phone.number(), + })); + + const columns: ColumnDef<(typeof data)[0]>[] = [ + { + header: 'First Name', + accessorKey: 'firstName', + }, + { + header: 'Last Name', + accessorKey: 'lastName', + }, + { + header: 'Address', + accessorKey: 'address', + }, + { + header: 'State', + accessorKey: 'state', + }, + { + header: 'Phone Number', + accessorKey: 'phoneNumber', + }, + ]; + + return ( + + ); +}; + +export const ColumnPinning = () => { + const data = [...Array.from({ length: 100 })].map(() => ({ + firstName: faker.name.firstName(), + lastName: faker.name.lastName(), + email: faker.internet.email(), + address: faker.address.streetAddress(), + city: faker.address.city(), + state: faker.address.state(), + })); + + const columns: ColumnDef<(typeof data)[0]>[] = [ + { + header: 'First Name', + accessorKey: 'firstName', + }, + { + header: 'Last Name', + accessorKey: 'lastName', + }, + { + header: 'Email Address', + accessorKey: 'email', + }, + { + header: 'Address', + accessorKey: 'address', + }, + { + header: 'City', + accessorKey: 'city', + }, + { + header: 'State', + accessorKey: 'state', + }, + ]; + + return ( + + ); +}; + +export const RowSelection = () => { + const data = [...Array.from({ length: 15 })].map(() => ({ + firstName: faker.name.firstName(), + lastName: faker.name.lastName(), + age: faker.datatype.number(80), + address: faker.address.streetAddress(), + })); + + const columns: ColumnDef<(typeof data)[0]>[] = [ + { + header: 'First Name', + accessorKey: 'firstName', + }, + { + header: 'Last Name', + accessorKey: 'lastName', + }, + { + header: 'Age', + accessorKey: 'age', + }, + { + header: 'Address', + accessorKey: 'address', + }, + ]; + + return ; +}; + +export const RowExpanding = () => { + const columns: ColumnDef<(typeof data)[0]>[] = [ + { + header: 'First Name', + accessorKey: 'firstName', + }, + { + header: 'Last Name', + accessorKey: 'lastName', + }, + { + header: 'Age', + accessorKey: 'age', + }, + { + header: 'Address', + accessorKey: 'address', + }, + { + header: 'Phone Number', + accessorKey: 'phoneNumber', + }, + ]; + + const data = [...Array.from({ length: 5 })].map(() => ({ + firstName: faker.name.firstName(), + lastName: faker.name.lastName(), + age: faker.datatype.number(80), + address: faker.address.streetAddress(), + phoneNumber: faker.phone.number(), + subRows: [...Array.from({ length: faker.datatype.number(4) })].map(() => ({ + firstName: faker.name.firstName(), + lastName: faker.name.lastName(), + age: faker.datatype.number(80), + address: faker.address.streetAddress(), + phoneNumber: faker.phone.number(), + })), + })); + + return ; +}; + +export const Loading = () => { + const data = [...Array.from({ length: 100 })].map(() => ({ + firstName: faker.name.firstName(), + lastName: faker.name.lastName(), + email: faker.internet.email(), + address: faker.address.streetAddress(), + city: faker.address.city(), + state: faker.address.state(), + })); + + const columns: ColumnDef<(typeof data)[0]>[] = [ + { + header: 'First Name', + accessorKey: 'firstName', + }, + { + header: 'Last Name', + accessorKey: 'lastName', + }, + { + header: 'Email Address', + accessorKey: 'email', + size: 300, + }, + { + header: 'Address', + accessorKey: 'address', + }, + { + header: 'City', + accessorKey: 'city', + }, + { + header: 'State', + accessorKey: 'state', + }, + ]; + + return ; +}; diff --git a/yarn.lock b/yarn.lock index c86b10a2e..ebecbf27a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3040,6 +3040,13 @@ __metadata: languageName: node linkType: hard +"@faker-js/faker@npm:^7.6.0": + version: 7.6.0 + resolution: "@faker-js/faker@npm:7.6.0" + checksum: 942af6221774e8c98a0eb6bc75265e05fb81a941170377666c3439aab9495dd321d6beedc5406f07e6ad44262b3e43c20961f666d116ad150b78e7437dd1bb2b + languageName: node + linkType: hard + "@formatjs/ecma402-abstract@npm:1.11.10": version: 1.11.10 resolution: "@formatjs/ecma402-abstract@npm:1.11.10" @@ -4130,6 +4137,7 @@ __metadata: "@react-stately/tree": ^3.4.1 "@react-stately/utils": ^3.6.0 "@react-types/shared": ^3.16.0 + "@tanstack/react-table": ^8.8.5 "@types/lodash.isobject": ^3.0.7 "@types/react-transition-group": ^4.4.5 clsx: ^1.2.1 @@ -7194,6 +7202,25 @@ __metadata: languageName: node linkType: hard +"@tanstack/react-table@npm:^8.8.5": + version: 8.8.5 + resolution: "@tanstack/react-table@npm:8.8.5" + dependencies: + "@tanstack/table-core": 8.8.5 + peerDependencies: + react: ">=16" + react-dom: ">=16" + checksum: 6c396b1a175699b8ebca56e81230194b03d94df5a83bde542a643363dfa40065e8fa795ef57bb8d540134d717538c420d7013e3d3cf7b8a93a0680d0d6192765 + languageName: node + linkType: hard + +"@tanstack/table-core@npm:8.8.5": + version: 8.8.5 + resolution: "@tanstack/table-core@npm:8.8.5" + checksum: 7bbf00635e57294dd5bd12d82efb273d3b68c47b905a1d7f2fdabe83d9c10314e67d24f918b570ba8fecf80a120008359c52682cdd917d9de26eeece31c43a7d + languageName: node + linkType: hard + "@testing-library/dom@npm:^8.11.1, @testing-library/dom@npm:^8.5.0": version: 8.19.1 resolution: "@testing-library/dom@npm:8.19.1" @@ -17738,6 +17765,7 @@ __metadata: "@changesets/cli": ^2.22.0 "@commitlint/cli": ^17.0.0 "@commitlint/config-conventional": ^17.0.0 + "@faker-js/faker": ^7.6.0 "@percy/cli": ^1.16.0 "@percy/storybook": ^4.3.4 "@swc/core": ^1.3.59