@sikka/hawa 0.0.266 → 0.0.268

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,12 +10,22 @@ import { BsChevronRight, BsFilter, BsPlus, BsThreeDots } from "react-icons/bs"
10
10
  // TODO: translate header tools and make it more customizable
11
11
  // TODO: pass the onSearch handler to the parent
12
12
 
13
+ type RowTypes = {
14
+ hidden: boolean
15
+ value: any
16
+ suffix?: any
17
+ }
18
+ type ColTypes = {
19
+ hidden: boolean
20
+ value: any
21
+ sortable?: boolean
22
+ }
13
23
  type TableTypes = {
14
24
  pagination?: boolean
15
- columns: any[string]
25
+ columns: ColTypes[]
16
26
  actions?: ActionItems[][]
17
27
  direction?: "rtl" | "ltr"
18
- rows?: any[any]
28
+ rows?: RowTypes[][]
19
29
  handleActionClick?: any
20
30
  end?: any
21
31
  size?: "normal" | "small"
@@ -57,8 +67,56 @@ export const HawaTable: FC<TableTypes> = ({
57
67
  const [perPage, setPerPage] = useState(10)
58
68
  const [enteredPage, setEnteredPage] = useState(null)
59
69
  const [page, setPage] = useState(1)
70
+ const [sortingCol, setSortingCol] = useState(null)
71
+
72
+ const [sortedRows, setSortedRows] = useState(props.rows)
73
+ const [sortColumn, setSortColumn] = useState(null)
74
+ const [sortDirection, setSortDirection] = useState(null)
75
+
76
+ const handleSort = (colIndex, sortable) => {
77
+ if (sortable) {
78
+ setSortColumn(colIndex)
79
+ setSortDirection((prevDirection) =>
80
+ prevDirection === "asc" ? "desc" : "asc"
81
+ )
82
+ }
83
+ // const newDirection =
84
+ // sortColumn === colIndex && sortDirection === "asc" ? "desc" : "asc"
85
+
86
+ // const sortedData = [...sortedRows].sort((a, b) => {
87
+ // const aValue = a[colIndex].value
88
+ // const bValue = b[colIndex].value
89
+
90
+ // // You can enhance the sorting logic based on the data type
91
+ // if (newDirection === "asc") {
92
+ // return aValue.localeCompare(bValue)
93
+ // } else {
94
+ // return bValue.localeCompare(aValue)
95
+ // }
96
+ // })
97
+
98
+ // setSortedRows(sortedData)
99
+ // setSortColumn(colIndex)
100
+ // setSortDirection(newDirection)
101
+ }
102
+
103
+ // const { slice, range } = useTable(props.rows, page, perPage)
104
+ // Use the custom hook to get paginated and sorted data
105
+ const { slice, range } = useTable(
106
+ props.rows,
107
+ page,
108
+ perPage,
109
+ sortColumn,
110
+ sortDirection
111
+ )
112
+ let isRTL = direction === "rtl"
113
+
114
+ let sizeStyles = {
115
+ normal: "py-3 px-6",
116
+ small: "px-3 py-1",
117
+ }
118
+ // let sortedRows = props.rows
60
119
 
61
- const { slice, range } = useTable(props.rows, page, perPage)
62
120
  const changePage = () => {
63
121
  if (slice?.length < 1 && page !== 1) {
64
122
  setPage(page - 1)
@@ -70,14 +128,6 @@ export const HawaTable: FC<TableTypes> = ({
70
128
  useEffect(() => {
71
129
  changePage()
72
130
  }, [slice, page])
73
-
74
- let isRTL = direction === "rtl"
75
-
76
- let sizeStyles = {
77
- normal: "py-3 px-6",
78
- small: "px-3 py-1",
79
- }
80
-
81
131
  return (
82
132
  <div className="relative flex flex-col gap-2 ">
83
133
  <div className={`overflow-x-auto rounded bg-${headerColor}`}>
@@ -124,10 +174,14 @@ export const HawaTable: FC<TableTypes> = ({
124
174
  } else {
125
175
  return (
126
176
  <th
177
+ onClick={() =>
178
+ col.sortable && handleSort(i, col.sortable)
179
+ }
127
180
  key={i}
128
181
  scope="col"
129
182
  colSpan={2}
130
183
  className={clsx(
184
+ col.sortable ? "cursor-pointer hover:bg-gray-300" : "",
131
185
  sizeStyles[size],
132
186
  i !== 0 &&
133
187
  (borders === "cols" ||
@@ -137,7 +191,11 @@ export const HawaTable: FC<TableTypes> = ({
137
191
  : ""
138
192
  )}
139
193
  >
194
+ {/* TODO: add arrow icon for sorting */}
140
195
  {col.value}
196
+ {sortColumn === i && (
197
+ <span>{sortDirection === "asc" ? " ▲" : " ▼"}</span>
198
+ )}
141
199
  </th>
142
200
  )
143
201
  }
@@ -158,7 +216,7 @@ export const HawaTable: FC<TableTypes> = ({
158
216
  }
159
217
  >
160
218
  {/* Table Rows */}
161
- {props.rows ? (
219
+ {sortedRows ? (
162
220
  slice?.map((singleRow: any, rowIndex: any) => {
163
221
  let lastRow = rowIndex == slice?.length - 1
164
222
  return (
@@ -224,7 +282,7 @@ export const HawaTable: FC<TableTypes> = ({
224
282
  // bodyColor ? `bg-${bodyColor}` : "bg-white"
225
283
  )}
226
284
  >
227
- {r.value}
285
+ {r.value} {r.suffix && r.suffix}
228
286
  </td>
229
287
  )
230
288
  }
@@ -1,3 +1,4 @@
1
+ // useTable.js
1
2
  import React, { useState, useEffect } from "react"
2
3
 
3
4
  const calculateRange = (data, rowsPerPage) => {
@@ -14,7 +15,33 @@ const sliceData = (data, page, rowsPerPage) => {
14
15
  return data?.slice((page - 1) * rowsPerPage, page * rowsPerPage)
15
16
  }
16
17
 
17
- const useTable = (data, page, rowsPerPage) => {
18
+ // useTable.js
19
+ const sortData = (data, sortColumn, sortDirection) => {
20
+ if (sortColumn !== null) {
21
+ return data?.sort((a, b) => {
22
+ const aValue = a[sortColumn].value
23
+ const bValue = b[sortColumn].value
24
+
25
+ // Handle non-string values by using simple comparison
26
+ if (typeof aValue === "string" && typeof bValue === "string") {
27
+ if (sortDirection === "asc") {
28
+ return aValue.localeCompare(bValue)
29
+ } else {
30
+ return bValue.localeCompare(aValue)
31
+ }
32
+ } else {
33
+ if (sortDirection === "asc") {
34
+ return aValue - bValue
35
+ } else {
36
+ return bValue - aValue
37
+ }
38
+ }
39
+ })
40
+ }
41
+ return data
42
+ }
43
+
44
+ const useTable = (data, page, rowsPerPage, sortColumn, sortDirection) => {
18
45
  const [tableRange, setTableRange] = useState([])
19
46
  const [slice, setSlice] = useState([])
20
47
 
@@ -23,12 +50,110 @@ const useTable = (data, page, rowsPerPage) => {
23
50
  const range = calculateRange(data, rowsPerPage)
24
51
  setTableRange([...range])
25
52
 
26
- const slice = sliceData(data, page, rowsPerPage)
27
- setSlice([...slice])
53
+ const sortedData = sortData(data, sortColumn, sortDirection)
54
+ const slicedData = sliceData(sortedData, page, rowsPerPage)
55
+ setSlice([...slicedData])
28
56
  }
29
- }, [data, setTableRange, page, setSlice, rowsPerPage])
57
+ }, [data, setTableRange, page, rowsPerPage, sortColumn, sortDirection])
30
58
 
31
59
  return { slice, range: tableRange }
32
60
  }
33
61
 
34
62
  export default useTable
63
+
64
+ // import React, { useState, useEffect } from "react"
65
+
66
+ // const calculateRange = (data, rowsPerPage) => {
67
+ // const range = []
68
+ // const num = Math.ceil(data?.length / rowsPerPage)
69
+ // let i = 1
70
+ // for (let i = 1; i <= num; i++) {
71
+ // range.push(i)
72
+ // }
73
+ // return range
74
+ // }
75
+
76
+ // const sliceData = (data, page, rowsPerPage) => {
77
+ // return data?.slice((page - 1) * rowsPerPage, page * rowsPerPage)
78
+ // }
79
+
80
+ // const sortData = (data, sortColumn, sortDirection) => {
81
+ // if (sortColumn !== null) {
82
+ // return data?.sort((a, b) => {
83
+ // const aValue = a[sortColumn].value
84
+ // const bValue = b[sortColumn].value
85
+
86
+ // if (sortDirection === "asc") {
87
+ // return aValue.localeCompare(bValue)
88
+ // } else {
89
+ // return bValue.localeCompare(aValue)
90
+ // }
91
+ // })
92
+ // }
93
+ // return data
94
+ // }
95
+
96
+ // const useTable = (data, page, rowsPerPage, sortColumn, sortDirection) => {
97
+ // const [tableRange, setTableRange] = useState([])
98
+ // const [slice, setSlice] = useState([])
99
+
100
+ // useEffect(() => {
101
+ // if (data) {
102
+ // const range = calculateRange(data, rowsPerPage)
103
+ // setTableRange([...range])
104
+
105
+ // const sortedData = sortData(data, sortColumn, sortDirection)
106
+ // const slicedData = sliceData(sortedData, page, rowsPerPage)
107
+ // setSlice([...slicedData])
108
+ // }
109
+ // }, [data, setTableRange, page, rowsPerPage, sortColumn, sortDirection])
110
+
111
+ // return { slice, range: tableRange }
112
+ // }
113
+
114
+ // export default useTable
115
+ //
116
+ //
117
+ //
118
+ //
119
+ //
120
+ //
121
+ //
122
+ //
123
+ //
124
+ //
125
+
126
+ // import React, { useState, useEffect } from "react"
127
+
128
+ // const calculateRange = (data, rowsPerPage) => {
129
+ // const range = []
130
+ // const num = Math.ceil(data?.length / rowsPerPage)
131
+ // let i = 1
132
+ // for (let i = 1; i <= num; i++) {
133
+ // range.push(i)
134
+ // }
135
+ // return range
136
+ // }
137
+
138
+ // const sliceData = (data, page, rowsPerPage) => {
139
+ // return data?.slice((page - 1) * rowsPerPage, page * rowsPerPage)
140
+ // }
141
+
142
+ // const useTable = (data, page, rowsPerPage) => {
143
+ // const [tableRange, setTableRange] = useState([])
144
+ // const [slice, setSlice] = useState([])
145
+
146
+ // useEffect(() => {
147
+ // if (data) {
148
+ // const range = calculateRange(data, rowsPerPage)
149
+ // setTableRange([...range])
150
+
151
+ // const slice = sliceData(data, page, rowsPerPage)
152
+ // setSlice([...slice])
153
+ // }
154
+ // }, [data, setTableRange, page, setSlice, rowsPerPage])
155
+
156
+ // return { slice, range: tableRange }
157
+ // }
158
+
159
+ // export default useTable
@@ -0,0 +1,123 @@
1
+ import React, { useEffect, FC, useRef, useState } from "react"
2
+ import clsx from "clsx"
3
+ import { HawaButton } from "../elements"
4
+
5
+ type BannerTypes = {
6
+ showBanner?: boolean
7
+ direction?: "rtl" | "ltr"
8
+ logoURL?: string
9
+ title?: string
10
+ text?: string
11
+ actionText?: string
12
+ onActionClick?: () => void
13
+ position?: "top" | "bottom"
14
+ design: "default" | "floating"
15
+ }
16
+
17
+ export const HawaBanner: FC<BannerTypes> = ({
18
+ design = "floating",
19
+ ...props
20
+ }) => {
21
+ const bannerRef = useRef(null)
22
+ const [closed, setClosed] = useState(false)
23
+ let bannerStyle = {
24
+ floating:
25
+ "left-1/2 z-50 w-[calc(100%-2rem)] -translate-x-1/2 lg:max-w-7xl p-4 rounded",
26
+ default: "w-[calc(100%)] left-0 z-50 right-0 rounded-none p-2",
27
+ }
28
+ return (
29
+ <div ref={bannerRef}>
30
+ <div
31
+ dir={props.direction}
32
+ className={clsx(
33
+ bannerStyle[design],
34
+ "fixed flex flex-col justify-between border border-gray-100 bg-white shadow-sm transition-all dark:border-gray-600 dark:bg-gray-700 md:flex-row md:gap-4 ",
35
+ props.position === "top"
36
+ ? design === "floating"
37
+ ? "top-6"
38
+ : "top-0"
39
+ : design === "floating"
40
+ ? "bottom-6"
41
+ : "bottom-0",
42
+ closed ? "opacity-0" : "opacity-100"
43
+ )}
44
+ >
45
+ <div className="mb-3 flex w-full flex-col items-center justify-start md:mb-0 md:flex-row md:items-center">
46
+ <div
47
+ className={clsx(
48
+ props.direction === "rtl"
49
+ ? "md:ml-4 md:border-l md:pl-4"
50
+ : "md:mr-4 md:border-r md:pr-4",
51
+ "mb-2 flex items-center border-gray-200 dark:border-gray-600 md:mb-0 md:mr-4 md:pr-4"
52
+ )}
53
+ >
54
+ {props.logoURL && (
55
+ <img
56
+ src={props.logoURL}
57
+ className="mr-2 h-6"
58
+ alt="Flowbite Logo"
59
+ />
60
+ )}
61
+ {props.title && (
62
+ <span className="self-center whitespace-nowrap text-lg font-semibold dark:text-white">
63
+ {props.title}
64
+ </span>
65
+ )}
66
+ </div>
67
+ {props.text && (
68
+ <p
69
+ className={clsx(
70
+ "m-0 flex items-center text-center text-sm font-normal text-gray-500 dark:text-gray-400 ",
71
+ props.direction === "rtl" ? "md:text-right" : "md:text-left"
72
+ )}
73
+ >
74
+ {props.text}
75
+ </p>
76
+ )}
77
+ </div>
78
+ {props.actionText && (
79
+ <div
80
+ className={clsx(
81
+ "flex flex-shrink-0 items-center justify-center ",
82
+ props.direction === "rtl" ? "ml-0 md:ml-10" : "mr-0 md:mr-10"
83
+ )}
84
+ >
85
+ <HawaButton onClick={props.onActionClick}>
86
+ {props.actionText}
87
+ </HawaButton>
88
+ </div>
89
+ )}
90
+ <button
91
+ type="button"
92
+ className={clsx(
93
+ "absolute top-2 inline-flex h-9 w-9 items-center justify-center rounded-inner p-1.5 text-gray-400 transition-all hover:text-gray-900 focus:ring-2 focus:ring-gray-300 dark:bg-gray-800 dark:text-gray-500 dark:hover:bg-gray-700 dark:hover:text-white",
94
+ props.direction === "rtl" ? "left-2" : "right-2"
95
+ )}
96
+ data-dismiss-target="#alert-default"
97
+ aria-label="Close"
98
+ onClick={() => {
99
+ setClosed(true)
100
+ setTimeout(() => {
101
+ bannerRef.current.removeChild(bannerRef.current.children[0])
102
+ }, 200)
103
+ }}
104
+ >
105
+ <span className="sr-only">Close</span>
106
+ <svg
107
+ aria-hidden="true"
108
+ className="h-5 w-5"
109
+ fill="currentColor"
110
+ viewBox="0 0 20 20"
111
+ xmlns="http://www.w3.org/2000/svg"
112
+ >
113
+ <path
114
+ fillRule="evenodd"
115
+ d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
116
+ clipRule="evenodd"
117
+ ></path>
118
+ </svg>
119
+ </button>
120
+ </div>
121
+ </div>
122
+ )
123
+ }
@@ -1,6 +1,5 @@
1
1
  import React, { useEffect, useRef, useState } from "react"
2
2
  import clsx from "clsx"
3
- import { HiMenu } from "react-icons/hi"
4
3
  import { FaChevronRight } from "react-icons/fa"
5
4
  import { FiSettings } from "react-icons/fi"
6
5
  import useDiscloser from "../hooks/useDiscloser"
@@ -136,8 +135,22 @@ export const HawaAppLayout: React.FunctionComponent<HawaAppLayoutTypes> = ({
136
135
  onClick={() => setOpenSideMenu(true)}
137
136
  className="z-40 mx-1 cursor-pointer rounded p-2 transition-all hover:bg-gray-100"
138
137
  >
139
- <HiMenu size={25} />
140
- </div>
138
+ <svg
139
+ stroke="currentColor"
140
+ fill="currentColor"
141
+ stroke-width="0"
142
+ viewBox="0 0 20 20"
143
+ aria-hidden="true"
144
+ height="1.6em"
145
+ width="1.6em"
146
+ xmlns="http://www.w3.org/2000/svg"
147
+ >
148
+ <path
149
+ fill-rule="evenodd"
150
+ d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
151
+ clip-rule="evenodd"
152
+ ></path>
153
+ </svg> </div>
141
154
  {/* Mobile Page Title */}
142
155
  {props.pageTitle ? (
143
156
  <div className="text-sm">{props.pageTitle}</div>
@@ -1,6 +1,5 @@
1
1
  import React, { useEffect, useRef, useState } from "react"
2
2
  import clsx from "clsx"
3
- import { HiMenu } from "react-icons/hi"
4
3
  import useDiscloser from "../hooks/useDiscloser"
5
4
  import useBreakpoint from "../hooks/useBreakpoint"
6
5
  import { HawaMenu } from "../elements"
@@ -135,7 +134,22 @@ export const HawaAppLayoutSimplified: React.FunctionComponent<
135
134
  onClick={() => setOpenSideMenu(true)}
136
135
  className="z-40 mx-1 cursor-pointer rounded p-2 transition-all hover:bg-gray-100"
137
136
  >
138
- <HiMenu size={25} />
137
+ <svg
138
+ stroke="currentColor"
139
+ fill="currentColor"
140
+ stroke-width="0"
141
+ viewBox="0 0 20 20"
142
+ aria-hidden="true"
143
+ height="1.6em"
144
+ width="1.6em"
145
+ xmlns="http://www.w3.org/2000/svg"
146
+ >
147
+ <path
148
+ fill-rule="evenodd"
149
+ d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
150
+ clip-rule="evenodd"
151
+ ></path>
152
+ </svg>
139
153
  </div>
140
154
  {/* Mobile Page Title */}
141
155
  {props.pageTitle ? (
@@ -316,6 +330,14 @@ export const HawaAppLayoutSimplified: React.FunctionComponent<
316
330
  </div>
317
331
  {dItem.subItems && (
318
332
  <ArrowIcon
333
+ color={
334
+ props.currentPage === dItem.slug ||
335
+ dItem.subItems?.find(
336
+ (e) => e.slug === props.currentPage
337
+ )
338
+ ? "white"
339
+ : "black"
340
+ }
319
341
  pointing={
320
342
  openSubItem && dItem.slug === openSubItem
321
343
  ? "up"
@@ -328,7 +350,7 @@ export const HawaAppLayoutSimplified: React.FunctionComponent<
328
350
  {dItem.subItems && (
329
351
  <div
330
352
  className={clsx(
331
- "m-1 mx-2 flex cursor-pointer flex-col gap-0 overflow-clip whitespace-nowrap rounded bg-layoutPrimary-300 p-1 transition-all",
353
+ "m-1 mx-2 flex cursor-pointer flex-col gap-1 overflow-clip whitespace-nowrap rounded bg-layoutPrimary-300 p-1 transition-all",
332
354
  openSubItem == dItem.slug && openSideMenu
333
355
  ? ""
334
356
  : "my-0 py-0",
@@ -337,7 +359,7 @@ export const HawaAppLayoutSimplified: React.FunctionComponent<
337
359
  style={{
338
360
  height:
339
361
  openSubItem == dItem.slug && openSideMenu
340
- ? 6 + 33 * dItem.subItems?.length
362
+ ? 6 + 35 * dItem.subItems?.length
341
363
  : 0,
342
364
  }}
343
365
  >
@@ -430,6 +452,7 @@ export const HawaAppLayoutSimplified: React.FunctionComponent<
430
452
  }
431
453
  >
432
454
  <ArrowIcon
455
+ color={"black"}
433
456
  pointing={
434
457
  keepOpen
435
458
  ? isRTL
@@ -488,7 +511,7 @@ const AvatarIcon = () => (
488
511
  </svg>
489
512
  )
490
513
 
491
- const ArrowIcon = ({ pointing }) => {
514
+ const ArrowIcon = ({ pointing, color }) => {
492
515
  let directionStyle
493
516
  switch (pointing) {
494
517
  case "right":
@@ -513,6 +536,7 @@ const ArrowIcon = ({ pointing }) => {
513
536
  "h-6 w-6 shrink-0 transition-all disabled:bg-gray-200",
514
537
  directionStyle
515
538
  )}
539
+ fill={color}
516
540
  viewBox="0 0 20 20"
517
541
  xmlns="http://www.w3.org/2000/svg"
518
542
  >
@@ -1,7 +1,6 @@
1
1
  import React, { useEffect, useRef, useState } from "react"
2
2
  import clsx from "clsx"
3
3
  import useDiscloser from "../hooks/useDiscloser"
4
- import { HiMenu } from "react-icons/hi"
5
4
  import useBreakpoint from "../hooks/useBreakpoint"
6
5
 
7
6
  type HawaSiteLayoutTypes = {
@@ -117,8 +116,22 @@ export const HawaSiteLayout: React.FunctionComponent<HawaSiteLayoutTypes> = ({
117
116
  onClick={() => setOpenSideMenu(!openSideMenu)}
118
117
  className="cursor-pointer rounded p-1 transition-all hover:bg-gray-100"
119
118
  >
120
- <HiMenu size={25} />
121
- </div>
119
+ <svg
120
+ stroke="currentColor"
121
+ fill="currentColor"
122
+ stroke-width="0"
123
+ viewBox="0 0 20 20"
124
+ aria-hidden="true"
125
+ height="1.6em"
126
+ width="1.6em"
127
+ xmlns="http://www.w3.org/2000/svg"
128
+ >
129
+ <path
130
+ fill-rule="evenodd"
131
+ d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
132
+ clip-rule="evenodd"
133
+ ></path>
134
+ </svg> </div>
122
135
  {props.pageTitle ? <div>{props.pageTitle}</div> : <div></div>}
123
136
  </div>
124
137
  )}
@@ -6,3 +6,4 @@ export * from "./HawaAppLayoutSimplified"
6
6
  export * from "./HawaContainer"
7
7
  export * from "./AppSidebar"
8
8
  export * from "./Footer"
9
+ export * from "./Banner"