@scripso-homepad/ui 0.4.1 → 0.4.3

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.
Files changed (86) hide show
  1. package/dist/{chunk-C7GHBVMM.js → chunk-66WR57JJ.js} +53 -10
  2. package/dist/chunk-66WR57JJ.js.map +1 -0
  3. package/dist/index.cjs +2297 -391
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +144 -2
  6. package/dist/index.d.ts +144 -2
  7. package/dist/index.js +1978 -96
  8. package/dist/index.js.map +1 -1
  9. package/dist/web/index.cjs +30411 -759
  10. package/dist/web/index.cjs.map +1 -1
  11. package/dist/web/index.css +78 -0
  12. package/dist/web/index.css.map +1 -0
  13. package/dist/web/index.d.cts +267 -6
  14. package/dist/web/index.d.ts +267 -6
  15. package/dist/web/index.js +30179 -601
  16. package/dist/web/index.js.map +1 -1
  17. package/package.json +5 -4
  18. package/src/components/Calendar.stories.tsx +337 -0
  19. package/src/components/Calendar.tsx +441 -0
  20. package/src/components/DatePicker.stories.tsx +219 -0
  21. package/src/components/DatePicker.tsx +366 -0
  22. package/src/components/Input.tsx +5 -1
  23. package/src/components/Select.stories.tsx +134 -0
  24. package/src/components/Select.tsx +462 -0
  25. package/src/css.d.ts +1 -0
  26. package/src/icons/CalendarIcon.tsx +28 -0
  27. package/src/icons/CalendarIcon.web.tsx +34 -0
  28. package/src/icons/ChevronDownIcon.tsx +11 -4
  29. package/src/icons/ChevronDownIcon.web.tsx +6 -4
  30. package/src/icons/ChevronNavIcons.tsx +44 -0
  31. package/src/icons/ChevronNavIcons.web.tsx +57 -0
  32. package/src/icons/LockIcon.tsx +30 -0
  33. package/src/icons/LockIcon.web.tsx +35 -0
  34. package/src/icons/calendarIconPaths.ts +2 -0
  35. package/src/icons/chevronDownPath.ts +1 -0
  36. package/src/icons/chevronNavPaths.ts +2 -0
  37. package/src/icons/lockIconPaths.ts +2 -0
  38. package/src/index.ts +43 -0
  39. package/src/theme/calendar.ts +357 -0
  40. package/src/theme/input.ts +16 -6
  41. package/src/theme/select.ts +249 -0
  42. package/src/utils/calendarDays.ts +273 -0
  43. package/src/utils/calendarLocaleContext.tsx +95 -0
  44. package/src/utils/calendarLocalization.ts +187 -0
  45. package/src/utils/countryDropdownScrollStyles.ts +53 -13
  46. package/src/utils/formatMultiSelectDisplay.ts +56 -0
  47. package/src/web/components/Badge.stories.tsx +43 -0
  48. package/src/web/components/Badge.tsx +35 -0
  49. package/src/web/components/Pagination.stories.tsx +78 -0
  50. package/src/web/components/Pagination.tsx +153 -0
  51. package/src/web/components/StatusBadge.tsx +20 -0
  52. package/src/web/components/Table.stories.tsx +415 -0
  53. package/src/web/components/Table.tsx +3 -0
  54. package/src/web/components/TableActionButton.tsx +67 -0
  55. package/src/web/components/TableActionsMenu.tsx +208 -0
  56. package/src/web/components/TableIconText.tsx +23 -0
  57. package/src/web/components/TableRowStatusActions.tsx +33 -0
  58. package/src/web/components/TableStatusActionsCell.tsx +29 -0
  59. package/src/web/components/pagination-utils.ts +39 -0
  60. package/src/web/components/table/DataTable.tsx +123 -0
  61. package/src/web/components/table/TablePrimitives.tsx +214 -0
  62. package/src/web/components/table/TableScrollArea.tsx +51 -0
  63. package/src/web/components/table/constants.ts +59 -0
  64. package/src/web/components/table/data-table-class-names.ts +26 -0
  65. package/src/web/components/table/index.ts +44 -0
  66. package/src/web/components/table/table-row-context.tsx +19 -0
  67. package/src/web/components/table/use-horizontal-scroll-state.ts +72 -0
  68. package/src/web/components/table-scroll.css +81 -0
  69. package/src/web/hooks/useOnClickOutside.ts +20 -5
  70. package/src/web/icons/TableMenuActivateIcon.tsx +27 -0
  71. package/src/web/icons/TableMenuCheckIcon.tsx +27 -0
  72. package/src/web/icons/TableMenuCloseIcon.tsx +27 -0
  73. package/src/web/icons/TableMenuEditIcon.tsx +27 -0
  74. package/src/web/icons/TableMenuInfoIcon.tsx +27 -0
  75. package/src/web/icons/TableMenuRefreshIcon.tsx +27 -0
  76. package/src/web/icons/TableMenuSuspendIcon.tsx +34 -0
  77. package/src/web/icons/TableMenuTrashIcon.tsx +27 -0
  78. package/src/web/icons/TableMoreIcon.tsx +41 -0
  79. package/src/web/icons/TableSortIcon.tsx +37 -0
  80. package/src/web/index.ts +74 -0
  81. package/src/web/layout/AppHeader.stories.tsx +2 -0
  82. package/src/web/layout/AppHeader.tsx +18 -14
  83. package/src/web/layout/DashboardLayout.stories.tsx +1 -0
  84. package/src/web/layout/DashboardLayout.tsx +8 -4
  85. package/src/web/layout/story-helpers.tsx +10 -2
  86. package/dist/chunk-C7GHBVMM.js.map +0 -1
@@ -0,0 +1,72 @@
1
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
2
+
3
+ export type HorizontalScrollState = {
4
+ hasOverflow: boolean;
5
+ atEnd: boolean;
6
+ };
7
+
8
+ const useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
9
+
10
+ function getHorizontalScrollState(element: HTMLElement): HorizontalScrollState {
11
+ const inner = element.firstElementChild as HTMLElement | null;
12
+ const table = inner?.querySelector('table');
13
+ const contentWidth = table?.scrollWidth ?? inner?.scrollWidth ?? element.scrollWidth;
14
+ const viewportWidth = element.clientWidth;
15
+ const maxScrollLeft = element.scrollWidth - element.clientWidth;
16
+ const hasOverflow = contentWidth > viewportWidth + 1;
17
+ const atEnd = !hasOverflow || element.scrollLeft >= maxScrollLeft - 1;
18
+
19
+ return { hasOverflow, atEnd };
20
+ }
21
+
22
+ export function useHorizontalScrollState() {
23
+ const scrollRef = useRef<HTMLDivElement>(null);
24
+ const [scrollState, setScrollState] = useState<HorizontalScrollState>({
25
+ hasOverflow: false,
26
+ atEnd: true,
27
+ });
28
+
29
+ const updateScrollState = useCallback(() => {
30
+ const element = scrollRef.current;
31
+ if (!element) {
32
+ return;
33
+ }
34
+
35
+ setScrollState(getHorizontalScrollState(element));
36
+ }, []);
37
+
38
+ useIsomorphicLayoutEffect(() => {
39
+ const element = scrollRef.current;
40
+ if (!element) {
41
+ return;
42
+ }
43
+
44
+ updateScrollState();
45
+
46
+ element.addEventListener('scroll', updateScrollState, { passive: true });
47
+
48
+ if (typeof ResizeObserver === 'undefined') {
49
+ window.addEventListener('resize', updateScrollState);
50
+
51
+ return () => {
52
+ element.removeEventListener('scroll', updateScrollState);
53
+ window.removeEventListener('resize', updateScrollState);
54
+ };
55
+ }
56
+
57
+ const resizeObserver = new ResizeObserver(updateScrollState);
58
+ resizeObserver.observe(element);
59
+
60
+ const inner = element.firstElementChild;
61
+ if (inner) {
62
+ resizeObserver.observe(inner);
63
+ }
64
+
65
+ return () => {
66
+ element.removeEventListener('scroll', updateScrollState);
67
+ resizeObserver.disconnect();
68
+ };
69
+ }, [updateScrollState]);
70
+
71
+ return { scrollRef, scrollState };
72
+ }
@@ -0,0 +1,81 @@
1
+ .table-scroll-area {
2
+ scrollbar-color: var(--color-storm-gray-50, #eceef0) transparent;
3
+ scrollbar-width: thin;
4
+ }
5
+
6
+ .table-scroll-area::-webkit-scrollbar {
7
+ width: 8px;
8
+ height: 8px;
9
+ -webkit-appearance: none;
10
+ appearance: none;
11
+ }
12
+
13
+ .table-scroll-area::-webkit-scrollbar-button,
14
+ .table-scroll-area::-webkit-scrollbar-button:single-button,
15
+ .table-scroll-area::-webkit-scrollbar-button:double-button,
16
+ .table-scroll-area::-webkit-scrollbar-button:horizontal:decrement,
17
+ .table-scroll-area::-webkit-scrollbar-button:horizontal:increment,
18
+ .table-scroll-area::-webkit-scrollbar-button:horizontal:start:decrement,
19
+ .table-scroll-area::-webkit-scrollbar-button:horizontal:end:increment,
20
+ .table-scroll-area::-webkit-scrollbar-button:vertical:decrement,
21
+ .table-scroll-area::-webkit-scrollbar-button:vertical:increment,
22
+ .table-scroll-area::-webkit-scrollbar-button:vertical:start:decrement,
23
+ .table-scroll-area::-webkit-scrollbar-button:vertical:end:increment,
24
+ .table-scroll-area::-webkit-scrollbar-button:start:decrement,
25
+ .table-scroll-area::-webkit-scrollbar-button:end:increment,
26
+ .table-scroll-area::-webkit-scrollbar-button:decrement,
27
+ .table-scroll-area::-webkit-scrollbar-button:increment {
28
+ display: none;
29
+ width: 0;
30
+ height: 0;
31
+ max-width: 0;
32
+ max-height: 0;
33
+ min-width: 0;
34
+ min-height: 0;
35
+ padding: 0;
36
+ margin: 0;
37
+ border: 0;
38
+ background: transparent;
39
+ -webkit-appearance: none;
40
+ appearance: none;
41
+ }
42
+
43
+ .table-scroll-area::-webkit-scrollbar-track {
44
+ background: transparent;
45
+ }
46
+
47
+ .table-scroll-area::-webkit-scrollbar-thumb {
48
+ background-color: var(--color-storm-gray-50, #eceef0);
49
+ border-radius: 51px;
50
+ }
51
+
52
+ .table-scroll-area::-webkit-scrollbar-corner {
53
+ background: transparent;
54
+ }
55
+
56
+ .table-sticky-right-shadow::before {
57
+ content: '';
58
+ position: absolute;
59
+ top: 0;
60
+ bottom: 0;
61
+ left: 0;
62
+ z-index: 0;
63
+ width: 12px;
64
+ transform: translateX(-100%);
65
+ background: linear-gradient(90deg, rgba(21, 26, 30, 0) 0%, rgba(21, 26, 30, 0.08) 100%);
66
+ pointer-events: none;
67
+ opacity: 0;
68
+ transition: opacity 150ms ease;
69
+ }
70
+
71
+ .table-scroll-has-overflow:not(.table-scroll-at-end) .table-sticky-right-shadow::before {
72
+ opacity: 1;
73
+ }
74
+
75
+ .table-sticky-right-head {
76
+ background-color: var(--color-storm-gray-0, #fbfcfc);
77
+ }
78
+
79
+ .table-scroll-has-overflow:not(.table-scroll-at-end) .table-sticky-right-head {
80
+ background-color: #fff;
81
+ }
@@ -1,10 +1,25 @@
1
- import { useEffect, type RefObject } from 'react';
1
+ import { useEffect, useRef, type RefObject } from 'react';
2
+
3
+ type OutsideTarget<T extends HTMLElement> = RefObject<T | null> | Array<RefObject<T | null>>;
4
+
5
+ function isEventInsideRefs<T extends HTMLElement>(
6
+ target: Node,
7
+ refs: Array<RefObject<T | null>>,
8
+ ): boolean {
9
+ return refs.some((ref) => ref.current?.contains(target));
10
+ }
2
11
 
3
12
  export function useOnClickOutside<T extends HTMLElement>(
4
- ref: RefObject<T | null>,
13
+ ref: OutsideTarget<T>,
5
14
  handler: () => void,
6
15
  enabled = true,
7
16
  ) {
17
+ const handlerRef = useRef(handler);
18
+ handlerRef.current = handler;
19
+
20
+ const refsRef = useRef<Array<RefObject<T | null>>>([]);
21
+ refsRef.current = Array.isArray(ref) ? ref : [ref];
22
+
8
23
  useEffect(() => {
9
24
  if (!enabled) {
10
25
  return;
@@ -12,11 +27,11 @@ export function useOnClickOutside<T extends HTMLElement>(
12
27
 
13
28
  const onPointerDown = (event: MouseEvent | TouchEvent) => {
14
29
  const target = event.target as Node | null;
15
- if (!ref.current || !target || ref.current.contains(target)) {
30
+ if (!target || isEventInsideRefs(target, refsRef.current)) {
16
31
  return;
17
32
  }
18
33
 
19
- handler();
34
+ handlerRef.current();
20
35
  };
21
36
 
22
37
  document.addEventListener('mousedown', onPointerDown);
@@ -26,5 +41,5 @@ export function useOnClickOutside<T extends HTMLElement>(
26
41
  document.removeEventListener('mousedown', onPointerDown);
27
42
  document.removeEventListener('touchstart', onPointerDown);
28
43
  };
29
- }, [enabled, handler, ref]);
44
+ }, [enabled]);
30
45
  }
@@ -0,0 +1,27 @@
1
+ import { cn } from '../utils/cn';
2
+
3
+ type TableMenuActivateIconProps = {
4
+ className?: string;
5
+ };
6
+
7
+ export function TableMenuActivateIcon({ className }: TableMenuActivateIconProps) {
8
+ return (
9
+ <svg
10
+ width="20"
11
+ height="20"
12
+ viewBox="0 0 20 20"
13
+ fill="none"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ aria-hidden
16
+ className={cn('shrink-0', className)}
17
+ >
18
+ <path
19
+ d="M14.1667 9.16699V6.66699C14.1667 4.3658 12.3012 2.50033 10 2.50033C7.69882 2.50033 5.83333 4.3658 5.83333 6.66699V9.16699M5.83333 9.16699H4.16667C3.24619 9.16699 2.5 9.91318 2.5 10.8337V16.667C2.5 17.5875 3.24619 18.3337 4.16667 18.3337H15.8333C16.7538 18.3337 17.5 17.5875 17.5 16.667V10.8337C17.5 9.91318 16.7538 9.16699 15.8333 9.16699H5.83333Z"
20
+ stroke="#279D54"
21
+ strokeWidth="1.75"
22
+ strokeLinecap="round"
23
+ strokeLinejoin="round"
24
+ />
25
+ </svg>
26
+ );
27
+ }
@@ -0,0 +1,27 @@
1
+ import { cn } from '../utils/cn';
2
+
3
+ type TableMenuCheckIconProps = {
4
+ className?: string;
5
+ };
6
+
7
+ export function TableMenuCheckIcon({ className }: TableMenuCheckIconProps) {
8
+ return (
9
+ <svg
10
+ width="20"
11
+ height="20"
12
+ viewBox="0 0 20 20"
13
+ fill="none"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ aria-hidden
16
+ className={cn('shrink-0', className)}
17
+ >
18
+ <path
19
+ d="M16.6693 5L7.5026 14.1667L3.33594 10"
20
+ stroke="#279D54"
21
+ strokeWidth="2"
22
+ strokeLinecap="round"
23
+ strokeLinejoin="round"
24
+ />
25
+ </svg>
26
+ );
27
+ }
@@ -0,0 +1,27 @@
1
+ import { cn } from '../utils/cn';
2
+
3
+ type TableMenuCloseIconProps = {
4
+ className?: string;
5
+ };
6
+
7
+ export function TableMenuCloseIcon({ className }: TableMenuCloseIconProps) {
8
+ return (
9
+ <svg
10
+ width="20"
11
+ height="20"
12
+ viewBox="0 0 20 20"
13
+ fill="none"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ aria-hidden
16
+ className={cn('shrink-0', className)}
17
+ >
18
+ <path
19
+ d="M15 5L5 15M5 5L15 15"
20
+ stroke="#AE0011"
21
+ strokeWidth="2"
22
+ strokeLinecap="round"
23
+ strokeLinejoin="round"
24
+ />
25
+ </svg>
26
+ );
27
+ }
@@ -0,0 +1,27 @@
1
+ import { cn } from '../utils/cn';
2
+
3
+ type TableMenuEditIconProps = {
4
+ className?: string;
5
+ };
6
+
7
+ export function TableMenuEditIcon({ className }: TableMenuEditIconProps) {
8
+ return (
9
+ <svg
10
+ width="20"
11
+ height="20"
12
+ viewBox="0 0 20 20"
13
+ fill="none"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ aria-hidden
16
+ className={cn('shrink-0', className)}
17
+ >
18
+ <path
19
+ d="M11.6667 3.33366L16.6667 8.33366M2.5 17.5003H5.83333L15.275 8.05866C15.5813 7.75244 15.7533 7.33612 15.7533 6.90233C15.7533 6.46854 15.5813 6.05222 15.275 5.746L14.2542 4.72533C13.9479 4.41911 13.5316 4.24707 13.0978 4.24707C12.664 4.24707 12.2477 4.41911 11.9415 4.72533L2.5 14.167V17.5003Z"
20
+ stroke="#B5BCC1"
21
+ strokeWidth="1.75"
22
+ strokeLinecap="round"
23
+ strokeLinejoin="round"
24
+ />
25
+ </svg>
26
+ );
27
+ }
@@ -0,0 +1,27 @@
1
+ import { cn } from '../utils/cn';
2
+
3
+ type TableMenuInfoIconProps = {
4
+ className?: string;
5
+ };
6
+
7
+ export function TableMenuInfoIcon({ className }: TableMenuInfoIconProps) {
8
+ return (
9
+ <svg
10
+ width="20"
11
+ height="20"
12
+ viewBox="0 0 20 20"
13
+ fill="none"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ aria-hidden
16
+ className={cn('shrink-0', className)}
17
+ >
18
+ <path
19
+ d="M9.9974 13.3337V10.0003M9.9974 6.66699H10.0057M18.3307 10.0003C18.3307 14.6027 14.5998 18.3337 9.9974 18.3337C5.39502 18.3337 1.66406 14.6027 1.66406 10.0003C1.66406 5.39795 5.39502 1.66699 9.9974 1.66699C14.5998 1.66699 18.3307 5.39795 18.3307 10.0003Z"
20
+ stroke="#B5BCC1"
21
+ strokeWidth="2"
22
+ strokeLinecap="round"
23
+ strokeLinejoin="round"
24
+ />
25
+ </svg>
26
+ );
27
+ }
@@ -0,0 +1,27 @@
1
+ import { cn } from '../utils/cn';
2
+
3
+ type TableMenuRefreshIconProps = {
4
+ className?: string;
5
+ };
6
+
7
+ export function TableMenuRefreshIcon({ className }: TableMenuRefreshIconProps) {
8
+ return (
9
+ <svg
10
+ width="20"
11
+ height="20"
12
+ viewBox="0 0 20 20"
13
+ fill="none"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ aria-hidden
16
+ className={cn('shrink-0', className)}
17
+ >
18
+ <path
19
+ d="M17.5 10C17.5 11.4834 17.0601 12.9334 16.236 14.1668C15.4119 15.4001 14.2406 16.3614 12.8701 16.9291C11.4997 17.4968 9.99168 17.6453 8.53683 17.3559C7.08197 17.0665 5.7456 16.3522 4.6967 15.3033C3.64781 14.2544 2.9335 12.918 2.64411 11.4632C2.35472 10.0083 2.50325 8.50032 3.07091 7.12987C3.63856 5.75943 4.59986 4.58809 5.83323 3.76398C7.0666 2.93987 8.51664 2.5 10 2.5C12.1 2.5 14.1083 3.33333 15.6167 4.78333L17.5 6.66667M13.3333 6.66667H17.5V2.5"
20
+ stroke="#082640"
21
+ strokeWidth="2"
22
+ strokeLinecap="round"
23
+ strokeLinejoin="round"
24
+ />
25
+ </svg>
26
+ );
27
+ }
@@ -0,0 +1,34 @@
1
+ import { cn } from '../utils/cn';
2
+
3
+ type TableMenuSuspendIconProps = {
4
+ className?: string;
5
+ };
6
+
7
+ export function TableMenuSuspendIcon({ className }: TableMenuSuspendIconProps) {
8
+ return (
9
+ <svg
10
+ width="20"
11
+ height="20"
12
+ viewBox="0 0 20 20"
13
+ fill="none"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ aria-hidden
16
+ className={cn('shrink-0', className)}
17
+ >
18
+ <path
19
+ d="M10 18.3337C14.6024 18.3337 18.3333 14.6027 18.3333 10.0003C18.3333 5.39795 14.6024 1.66699 10 1.66699C5.39763 1.66699 1.66667 5.39795 1.66667 10.0003C1.66667 14.6027 5.39763 18.3337 10 18.3337Z"
20
+ stroke="#AE0011"
21
+ strokeWidth="1.75"
22
+ strokeLinecap="round"
23
+ strokeLinejoin="round"
24
+ />
25
+ <path
26
+ d="M6.66667 10H13.3333"
27
+ stroke="#AE0011"
28
+ strokeWidth="1.75"
29
+ strokeLinecap="round"
30
+ strokeLinejoin="round"
31
+ />
32
+ </svg>
33
+ );
34
+ }
@@ -0,0 +1,27 @@
1
+ import { cn } from '../utils/cn';
2
+
3
+ type TableMenuTrashIconProps = {
4
+ className?: string;
5
+ };
6
+
7
+ export function TableMenuTrashIcon({ className }: TableMenuTrashIconProps) {
8
+ return (
9
+ <svg
10
+ width="20"
11
+ height="20"
12
+ viewBox="0 0 20 20"
13
+ fill="none"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ aria-hidden
16
+ className={cn('shrink-0', className)}
17
+ >
18
+ <path
19
+ d="M2.5 5.00033H17.5M15.8333 5.00033V16.667C15.8333 17.5003 15 18.3337 14.1667 18.3337H5.83333C5 18.3337 4.16667 17.5003 4.16667 16.667V5.00033M6.66667 5.00033V3.33366C6.66667 2.50033 7.5 1.66699 8.33333 1.66699H11.6667C12.5 1.66699 13.3333 2.50033 13.3333 3.33366V5.00033M8.33333 9.16699V14.167M11.6667 9.16699V14.167"
20
+ stroke="#AE0011"
21
+ strokeWidth="2"
22
+ strokeLinecap="round"
23
+ strokeLinejoin="round"
24
+ />
25
+ </svg>
26
+ );
27
+ }
@@ -0,0 +1,41 @@
1
+ import { cn } from '../utils/cn';
2
+
3
+ type TableMoreIconProps = {
4
+ className?: string;
5
+ };
6
+
7
+ export function TableMoreIcon({ className }: TableMoreIconProps) {
8
+ return (
9
+ <svg
10
+ width="24"
11
+ height="24"
12
+ viewBox="0 0 24 24"
13
+ fill="none"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ aria-hidden
16
+ className={cn('shrink-0 text-storm-gray-150', className)}
17
+ >
18
+ <path
19
+ d="M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z"
20
+ stroke="currentColor"
21
+ strokeWidth="2"
22
+ strokeLinecap="round"
23
+ strokeLinejoin="round"
24
+ />
25
+ <path
26
+ d="M19 13C19.5523 13 20 12.5523 20 12C20 11.4477 19.5523 11 19 11C18.4477 11 18 11.4477 18 12C18 12.5523 18.4477 13 19 13Z"
27
+ stroke="currentColor"
28
+ strokeWidth="2"
29
+ strokeLinecap="round"
30
+ strokeLinejoin="round"
31
+ />
32
+ <path
33
+ d="M5 13C5.55228 13 6 12.5523 6 12C6 11.4477 5.55228 11 5 11C4.44772 11 4 11.4477 4 12C4 12.5523 4.44772 13 5 13Z"
34
+ stroke="currentColor"
35
+ strokeWidth="2"
36
+ strokeLinecap="round"
37
+ strokeLinejoin="round"
38
+ />
39
+ </svg>
40
+ );
41
+ }
@@ -0,0 +1,37 @@
1
+ import { cn } from '../utils/cn';
2
+
3
+ export type TableSortDirection = 'asc' | 'desc';
4
+
5
+ type TableSortIconProps = {
6
+ direction?: TableSortDirection | null;
7
+ className?: string;
8
+ };
9
+
10
+ const inactiveFill = '#DADDE0';
11
+ const activeFill = '#6A7984';
12
+
13
+ export function TableSortIcon({ direction = null, className }: TableSortIconProps) {
14
+ const upFill = direction === 'asc' ? activeFill : inactiveFill;
15
+ const downFill = direction === 'desc' ? activeFill : inactiveFill;
16
+
17
+ return (
18
+ <svg
19
+ width="12"
20
+ height="19"
21
+ viewBox="0 0 12 19"
22
+ fill="none"
23
+ xmlns="http://www.w3.org/2000/svg"
24
+ aria-hidden
25
+ className={cn('shrink-0', className)}
26
+ >
27
+ <path
28
+ d="M9.70277 11.4541L6.42668 15.2773C6.37387 15.3389 6.30837 15.3883 6.23466 15.4222C6.16095 15.4561 6.08078 15.4736 5.99965 15.4736C5.91852 15.4736 5.83835 15.4561 5.76464 15.4222C5.69093 15.3883 5.62542 15.3389 5.57262 15.2773L2.29652 11.4541C1.98387 11.0892 2.24309 10.5255 2.72355 10.5255H9.27668C9.75715 10.5255 10.0164 11.0892 9.70277 11.4541Z"
29
+ fill={downFill}
30
+ />
31
+ <path
32
+ d="M2.29714 7.54504L5.57323 3.72191C5.62604 3.66032 5.69155 3.61088 5.76526 3.57699C5.83897 3.54309 5.91914 3.52554 6.00027 3.52554C6.0814 3.52554 6.16156 3.54309 6.23527 3.57699C6.30898 3.61088 6.37449 3.66032 6.4273 3.72191L9.70339 7.54504C10.016 7.90996 9.75683 8.47363 9.27636 8.47363H2.72323C2.24277 8.47363 1.98355 7.90996 2.29714 7.54504Z"
33
+ fill={upFill}
34
+ />
35
+ </svg>
36
+ );
37
+ }
package/src/web/index.ts CHANGED
@@ -21,6 +21,80 @@ export type { SidebarUserCardProps } from './layout/SidebarUserCard';
21
21
 
22
22
  export { BellIcon } from './icons/BellIcon';
23
23
  export { BuildingIcon } from './icons/BuildingIcon';
24
+ export { TableMoreIcon } from './icons/TableMoreIcon';
25
+ export { TableSortIcon } from './icons/TableSortIcon';
26
+ export { TableMenuCheckIcon } from './icons/TableMenuCheckIcon';
27
+ export { TableMenuCloseIcon } from './icons/TableMenuCloseIcon';
28
+ export { TableMenuInfoIcon } from './icons/TableMenuInfoIcon';
29
+ export { TableMenuRefreshIcon } from './icons/TableMenuRefreshIcon';
30
+ export { TableMenuActivateIcon } from './icons/TableMenuActivateIcon';
31
+ export { TableMenuEditIcon } from './icons/TableMenuEditIcon';
32
+ export { TableMenuSuspendIcon } from './icons/TableMenuSuspendIcon';
33
+ export { TableMenuTrashIcon } from './icons/TableMenuTrashIcon';
34
+
35
+ export { Pagination } from './components/Pagination';
36
+ export type { PaginationLabels, PaginationProps, PaginationVariant } from './components/Pagination';
37
+ export {
38
+ getPaginationRange,
39
+ getTotalPages,
40
+ getVisiblePageNumbers,
41
+ } from './components/pagination-utils';
42
+
43
+ export { TableRowStatusActions } from './components/TableRowStatusActions';
44
+ export type {
45
+ TableRowActionsConfig,
46
+ TableRowStatusActionsProps,
47
+ } from './components/TableRowStatusActions';
48
+
49
+ export { TableActionsMenu } from './components/TableActionsMenu';
50
+ export type {
51
+ TableActionsMenuItem,
52
+ TableActionsMenuItemTone,
53
+ TableActionsMenuProps,
54
+ } from './components/TableActionsMenu';
55
+
56
+ export { TableStatusActionsCell } from './components/TableStatusActionsCell';
57
+ export type { TableStatusActionsCellProps } from './components/TableStatusActionsCell';
58
+
59
+ export {
60
+ DataTable,
61
+ DEFAULT_TABLE_BODY_MIN_HEIGHT,
62
+ Table,
63
+ TableActionsCell,
64
+ TableBody,
65
+ TableCell,
66
+ TableHead,
67
+ TableHeader,
68
+ TableRow,
69
+ TableScrollArea,
70
+ tableRowDisabledCellClassName,
71
+ } from './components/Table';
72
+ export type {
73
+ DataTableClassNames,
74
+ DataTableProps,
75
+ TableActionsCellProps,
76
+ TableBodyProps,
77
+ TableCellProps,
78
+ TableCellVariant,
79
+ TableHeadProps,
80
+ TableHeaderProps,
81
+ TableProps,
82
+ TableRowProps,
83
+ TableScrollAreaProps,
84
+ TableSortDirection,
85
+ } from './components/Table';
86
+
87
+ export { Badge } from './components/Badge';
88
+ export type { BadgeProps, BadgeVariant } from './components/Badge';
89
+
90
+ export { StatusBadge } from './components/StatusBadge';
91
+ export type { StatusBadgeProps, StatusBadgeTone } from './components/StatusBadge';
92
+
93
+ export { TableActionButton } from './components/TableActionButton';
94
+ export type { TableActionButtonProps, TableActionButtonVariant } from './components/TableActionButton';
95
+
96
+ export { TableIconText } from './components/TableIconText';
97
+ export type { TableIconTextProps } from './components/TableIconText';
24
98
 
25
99
  export { useMediaQuery } from './hooks/useMediaQuery';
26
100
  export { useOnClickOutside } from './hooks/useOnClickOutside';
@@ -16,6 +16,7 @@ const meta = {
16
16
  args: {
17
17
  title: 'Dashboard',
18
18
  labels: storyLabels.header,
19
+ hasBuildingSelect: true,
19
20
  buildingOptions: storyBuildingOptions,
20
21
  selectedBuildingId: storyBuildingOptions[0].value,
21
22
  onBuildingChange: fn(),
@@ -73,6 +74,7 @@ export const InteractiveBuildingSelect: Story = {
73
74
 
74
75
  export const SingleBuildingDisabled: Story = {
75
76
  args: {
77
+ hasBuildingSelect: true,
76
78
  buildingOptions: [storyBuildingOptions[0]],
77
79
  selectedBuildingId: storyBuildingOptions[0].value,
78
80
  buildingSelectDisabled: true,
@@ -11,8 +11,9 @@ import type { AdminBuildingOption, AdminHeaderLabels } from './types';
11
11
  export type AppHeaderProps = {
12
12
  title: string;
13
13
  labels: AdminHeaderLabels;
14
- buildingOptions: AdminBuildingOption[];
15
- selectedBuildingId: string;
14
+ hasBuildingSelect?: boolean;
15
+ buildingOptions?: AdminBuildingOption[];
16
+ selectedBuildingId?: string;
16
17
  className?: string;
17
18
  buildingSelectClassName?: string;
18
19
  searchClassName?: string;
@@ -44,8 +45,9 @@ const defaultSearchFieldStyle: ViewStyle = {
44
45
  export function AppHeader({
45
46
  title,
46
47
  labels,
47
- buildingOptions,
48
- selectedBuildingId,
48
+ hasBuildingSelect = false,
49
+ buildingOptions = [],
50
+ selectedBuildingId = '',
49
51
  className,
50
52
  buildingSelectClassName,
51
53
  searchClassName,
@@ -73,16 +75,18 @@ export function AppHeader({
73
75
  <h1 className="truncate text-xl font-bold text-slate-blue">{title}</h1>
74
76
 
75
77
  <div className="flex shrink-0 items-center gap-3">
76
- <BuildingSelect
77
- options={buildingOptions}
78
- value={selectedBuildingId}
79
- labels={labels}
80
- onChange={onBuildingChange}
81
- disabled={buildingSelectDisabled}
82
- className={buildingSelectClassName}
83
- buildingIcon={buildingIcon}
84
- chevronIcon={buildingChevronIcon}
85
- />
78
+ {hasBuildingSelect ? (
79
+ <BuildingSelect
80
+ options={buildingOptions}
81
+ value={selectedBuildingId}
82
+ labels={labels}
83
+ onChange={onBuildingChange}
84
+ disabled={buildingSelectDisabled}
85
+ className={buildingSelectClassName}
86
+ buildingIcon={buildingIcon}
87
+ chevronIcon={buildingChevronIcon}
88
+ />
89
+ ) : null}
86
90
 
87
91
  <Input
88
92
  leftIcon={searchIcon ?? <Search strokeWidth={1.75} />}
@@ -58,6 +58,7 @@ function DashboardLayoutDemo() {
58
58
  header={{
59
59
  title: 'Dashboard',
60
60
  labels: storyLabels.header,
61
+ hasBuildingSelect: true,
61
62
  buildingOptions: storyBuildingOptions,
62
63
  selectedBuildingId,
63
64
  onBuildingChange: setSelectedBuildingId,