@refraktor/core 0.0.2 → 0.0.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 (217) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/build/components/breadcrumbs/breadcrumbs.d.ts +4 -0
  3. package/build/components/breadcrumbs/breadcrumbs.d.ts.map +1 -0
  4. package/build/components/breadcrumbs/breadcrumbs.js +64 -0
  5. package/build/components/breadcrumbs/breadcrumbs.styles.d.ts +12 -0
  6. package/build/components/breadcrumbs/breadcrumbs.styles.d.ts.map +1 -0
  7. package/build/components/breadcrumbs/breadcrumbs.styles.js +43 -0
  8. package/build/components/breadcrumbs/breadcrumbs.test.d.ts +2 -0
  9. package/build/components/breadcrumbs/breadcrumbs.test.d.ts.map +1 -0
  10. package/build/components/breadcrumbs/breadcrumbs.test.js +72 -0
  11. package/build/components/breadcrumbs/breadcrumbs.types.d.ts +56 -0
  12. package/build/components/breadcrumbs/breadcrumbs.types.d.ts.map +1 -0
  13. package/build/components/breadcrumbs/breadcrumbs.types.js +1 -0
  14. package/build/components/breadcrumbs/breadcrumbs.utils.d.ts +10 -0
  15. package/build/components/breadcrumbs/breadcrumbs.utils.d.ts.map +1 -0
  16. package/build/components/breadcrumbs/breadcrumbs.utils.js +36 -0
  17. package/build/components/breadcrumbs/index.d.ts +3 -0
  18. package/build/components/breadcrumbs/index.d.ts.map +1 -0
  19. package/build/components/breadcrumbs/index.js +1 -0
  20. package/build/components/drawer/drawer-close/drawer-close.d.ts +4 -0
  21. package/build/components/drawer/drawer-close/drawer-close.d.ts.map +1 -0
  22. package/build/components/drawer/drawer-close/drawer-close.js +19 -0
  23. package/build/components/drawer/drawer-close/index.d.ts +2 -0
  24. package/build/components/drawer/drawer-close/index.d.ts.map +1 -0
  25. package/build/components/drawer/drawer-close/index.js +1 -0
  26. package/build/components/drawer/drawer-content/drawer-content.d.ts +4 -0
  27. package/build/components/drawer/drawer-content/drawer-content.d.ts.map +1 -0
  28. package/build/components/drawer/drawer-content/drawer-content.js +41 -0
  29. package/build/components/drawer/drawer-content/index.d.ts +2 -0
  30. package/build/components/drawer/drawer-content/index.d.ts.map +1 -0
  31. package/build/components/drawer/drawer-content/index.js +1 -0
  32. package/build/components/drawer/drawer-header/drawer-header.d.ts +4 -0
  33. package/build/components/drawer/drawer-header/drawer-header.d.ts.map +1 -0
  34. package/build/components/drawer/drawer-header/drawer-header.js +13 -0
  35. package/build/components/drawer/drawer-header/index.d.ts +2 -0
  36. package/build/components/drawer/drawer-header/index.d.ts.map +1 -0
  37. package/build/components/drawer/drawer-header/index.js +1 -0
  38. package/build/components/drawer/drawer-overlay/drawer-overlay.d.ts +4 -0
  39. package/build/components/drawer/drawer-overlay/drawer-overlay.d.ts.map +1 -0
  40. package/build/components/drawer/drawer-overlay/drawer-overlay.js +31 -0
  41. package/build/components/drawer/drawer-overlay/index.d.ts +2 -0
  42. package/build/components/drawer/drawer-overlay/index.d.ts.map +1 -0
  43. package/build/components/drawer/drawer-overlay/index.js +1 -0
  44. package/build/components/drawer/drawer-root/drawer-root.d.ts +4 -0
  45. package/build/components/drawer/drawer-root/drawer-root.d.ts.map +1 -0
  46. package/build/components/drawer/drawer-root/drawer-root.js +50 -0
  47. package/build/components/drawer/drawer-root/index.d.ts +2 -0
  48. package/build/components/drawer/drawer-root/index.d.ts.map +1 -0
  49. package/build/components/drawer/drawer-root/index.js +1 -0
  50. package/build/components/drawer/drawer.context.d.ts +23 -0
  51. package/build/components/drawer/drawer.context.d.ts.map +1 -0
  52. package/build/components/drawer/drawer.context.js +2 -0
  53. package/build/components/drawer/drawer.d.ts +4 -0
  54. package/build/components/drawer/drawer.d.ts.map +1 -0
  55. package/build/components/drawer/drawer.js +19 -0
  56. package/build/components/drawer/drawer.styles.d.ts +6 -0
  57. package/build/components/drawer/drawer.styles.d.ts.map +1 -0
  58. package/build/components/drawer/drawer.styles.js +21 -0
  59. package/build/components/drawer/drawer.test.d.ts +2 -0
  60. package/build/components/drawer/drawer.test.d.ts.map +1 -0
  61. package/build/components/drawer/drawer.test.js +70 -0
  62. package/build/components/drawer/drawer.types.d.ts +116 -0
  63. package/build/components/drawer/drawer.types.d.ts.map +1 -0
  64. package/build/components/drawer/drawer.types.js +1 -0
  65. package/build/components/drawer/index.d.ts +8 -0
  66. package/build/components/drawer/index.d.ts.map +1 -0
  67. package/build/components/drawer/index.js +6 -0
  68. package/build/components/drawer/use-drawer.d.ts +17 -0
  69. package/build/components/drawer/use-drawer.d.ts.map +1 -0
  70. package/build/components/drawer/use-drawer.js +61 -0
  71. package/build/components/index.d.ts +4 -0
  72. package/build/components/index.d.ts.map +1 -1
  73. package/build/components/index.js +4 -0
  74. package/build/components/modal/modal-overlay/modal-overlay.d.ts.map +1 -1
  75. package/build/components/modal/modal-overlay/modal-overlay.js +10 -2
  76. package/build/components/modal/modal.test.js +16 -0
  77. package/build/components/modal/modal.types.d.ts +4 -0
  78. package/build/components/modal/modal.types.d.ts.map +1 -1
  79. package/build/components/segmented-control/index.d.ts +3 -0
  80. package/build/components/segmented-control/index.d.ts.map +1 -0
  81. package/build/components/segmented-control/index.js +1 -0
  82. package/build/components/segmented-control/segmented-control.d.ts +4 -0
  83. package/build/components/segmented-control/segmented-control.d.ts.map +1 -0
  84. package/build/components/segmented-control/segmented-control.js +113 -0
  85. package/build/components/segmented-control/segmented-control.styles.d.ts +9 -0
  86. package/build/components/segmented-control/segmented-control.styles.d.ts.map +1 -0
  87. package/build/components/segmented-control/segmented-control.styles.js +28 -0
  88. package/build/components/segmented-control/segmented-control.test.d.ts +2 -0
  89. package/build/components/segmented-control/segmented-control.test.d.ts.map +1 -0
  90. package/build/components/segmented-control/segmented-control.test.js +81 -0
  91. package/build/components/segmented-control/segmented-control.types.d.ts +49 -0
  92. package/build/components/segmented-control/segmented-control.types.d.ts.map +1 -0
  93. package/build/components/segmented-control/segmented-control.types.js +1 -0
  94. package/build/components/select/select-item/select-item.js +1 -1
  95. package/build/components/split-pane/index.d.ts +3 -0
  96. package/build/components/split-pane/index.d.ts.map +1 -0
  97. package/build/components/split-pane/index.js +1 -0
  98. package/build/components/split-pane/split-pane.d.ts +4 -0
  99. package/build/components/split-pane/split-pane.d.ts.map +1 -0
  100. package/build/components/split-pane/split-pane.js +201 -0
  101. package/build/components/split-pane/split-pane.styles.d.ts +3 -0
  102. package/build/components/split-pane/split-pane.styles.d.ts.map +1 -0
  103. package/build/components/split-pane/split-pane.styles.js +8 -0
  104. package/build/components/split-pane/split-pane.test.d.ts +2 -0
  105. package/build/components/split-pane/split-pane.test.d.ts.map +1 -0
  106. package/build/components/split-pane/split-pane.test.js +105 -0
  107. package/build/components/split-pane/split-pane.types.d.ts +51 -0
  108. package/build/components/split-pane/split-pane.types.d.ts.map +1 -0
  109. package/build/components/split-pane/split-pane.types.js +1 -0
  110. package/build/components/table/index.d.ts +9 -0
  111. package/build/components/table/index.d.ts.map +1 -0
  112. package/build/components/table/index.js +7 -0
  113. package/build/components/table/table-body/index.d.ts +2 -0
  114. package/build/components/table/table-body/index.d.ts.map +1 -0
  115. package/build/components/table/table-body/index.js +1 -0
  116. package/build/components/table/table-body/table-body.d.ts +4 -0
  117. package/build/components/table/table-body/table-body.d.ts.map +1 -0
  118. package/build/components/table/table-body/table-body.js +17 -0
  119. package/build/components/table/table-caption/index.d.ts +2 -0
  120. package/build/components/table/table-caption/index.d.ts.map +1 -0
  121. package/build/components/table/table-caption/index.js +1 -0
  122. package/build/components/table/table-caption/table-caption.d.ts +4 -0
  123. package/build/components/table/table-caption/table-caption.d.ts.map +1 -0
  124. package/build/components/table/table-caption/table-caption.js +13 -0
  125. package/build/components/table/table-cell/index.d.ts +2 -0
  126. package/build/components/table/table-cell/index.d.ts.map +1 -0
  127. package/build/components/table/table-cell/index.js +1 -0
  128. package/build/components/table/table-cell/table-cell.d.ts +4 -0
  129. package/build/components/table/table-cell/table-cell.d.ts.map +1 -0
  130. package/build/components/table/table-cell/table-cell.js +13 -0
  131. package/build/components/table/table-head/index.d.ts +2 -0
  132. package/build/components/table/table-head/index.d.ts.map +1 -0
  133. package/build/components/table/table-head/index.js +1 -0
  134. package/build/components/table/table-head/table-head.d.ts +4 -0
  135. package/build/components/table/table-head/table-head.d.ts.map +1 -0
  136. package/build/components/table/table-head/table-head.js +11 -0
  137. package/build/components/table/table-header-cell/index.d.ts +2 -0
  138. package/build/components/table/table-header-cell/index.d.ts.map +1 -0
  139. package/build/components/table/table-header-cell/index.js +1 -0
  140. package/build/components/table/table-header-cell/table-header-cell.d.ts +4 -0
  141. package/build/components/table/table-header-cell/table-header-cell.d.ts.map +1 -0
  142. package/build/components/table/table-header-cell/table-header-cell.js +13 -0
  143. package/build/components/table/table-row/index.d.ts +2 -0
  144. package/build/components/table/table-row/index.d.ts.map +1 -0
  145. package/build/components/table/table-row/index.js +1 -0
  146. package/build/components/table/table-row/table-row.d.ts +4 -0
  147. package/build/components/table/table-row/table-row.d.ts.map +1 -0
  148. package/build/components/table/table-row/table-row.js +11 -0
  149. package/build/components/table/table.context.d.ts +16 -0
  150. package/build/components/table/table.context.d.ts.map +1 -0
  151. package/build/components/table/table.context.js +2 -0
  152. package/build/components/table/table.d.ts +4 -0
  153. package/build/components/table/table.d.ts.map +1 -0
  154. package/build/components/table/table.js +46 -0
  155. package/build/components/table/table.styles.d.ts +16 -0
  156. package/build/components/table/table.styles.d.ts.map +1 -0
  157. package/build/components/table/table.styles.js +39 -0
  158. package/build/components/table/table.test.d.ts +2 -0
  159. package/build/components/table/table.test.d.ts.map +1 -0
  160. package/build/components/table/table.test.js +59 -0
  161. package/build/components/table/table.types.d.ts +113 -0
  162. package/build/components/table/table.types.d.ts.map +1 -0
  163. package/build/components/table/table.types.js +1 -0
  164. package/build/style.css +1 -1
  165. package/package.json +2 -2
  166. package/src/components/breadcrumbs/breadcrumbs.styles.ts +55 -0
  167. package/src/components/breadcrumbs/breadcrumbs.test.tsx +136 -0
  168. package/src/components/breadcrumbs/breadcrumbs.tsx +199 -0
  169. package/src/components/breadcrumbs/breadcrumbs.types.ts +78 -0
  170. package/src/components/breadcrumbs/breadcrumbs.utils.ts +70 -0
  171. package/src/components/breadcrumbs/index.ts +6 -0
  172. package/src/components/drawer/drawer-close/drawer-close.tsx +43 -0
  173. package/src/components/drawer/drawer-close/index.ts +1 -0
  174. package/src/components/drawer/drawer-content/drawer-content.tsx +98 -0
  175. package/src/components/drawer/drawer-content/index.ts +1 -0
  176. package/src/components/drawer/drawer-header/drawer-header.tsx +40 -0
  177. package/src/components/drawer/drawer-header/index.ts +1 -0
  178. package/src/components/drawer/drawer-overlay/drawer-overlay.tsx +86 -0
  179. package/src/components/drawer/drawer-overlay/index.ts +1 -0
  180. package/src/components/drawer/drawer-root/drawer-root.tsx +94 -0
  181. package/src/components/drawer/drawer-root/index.ts +1 -0
  182. package/src/components/drawer/drawer.context.ts +25 -0
  183. package/src/components/drawer/drawer.styles.ts +32 -0
  184. package/src/components/drawer/drawer.test.tsx +166 -0
  185. package/src/components/drawer/drawer.tsx +30 -0
  186. package/src/components/drawer/drawer.types.ts +158 -0
  187. package/src/components/drawer/index.ts +16 -0
  188. package/src/components/drawer/use-drawer.ts +101 -0
  189. package/src/components/index.ts +10 -6
  190. package/src/components/modal/modal-overlay/modal-overlay.tsx +43 -21
  191. package/src/components/modal/modal.test.tsx +47 -11
  192. package/src/components/modal/modal.types.ts +6 -0
  193. package/src/components/segmented-control/index.ts +6 -0
  194. package/src/components/segmented-control/segmented-control.styles.ts +37 -0
  195. package/src/components/segmented-control/segmented-control.test.tsx +152 -0
  196. package/src/components/segmented-control/segmented-control.tsx +245 -0
  197. package/src/components/segmented-control/segmented-control.types.ts +75 -0
  198. package/src/components/select/select-item/select-item.tsx +1 -1
  199. package/src/components/table/index.ts +24 -0
  200. package/src/components/table/table-body/index.ts +1 -0
  201. package/src/components/table/table-body/table-body.tsx +37 -0
  202. package/src/components/table/table-caption/index.ts +1 -0
  203. package/src/components/table/table-caption/table-caption.tsx +32 -0
  204. package/src/components/table/table-cell/index.ts +1 -0
  205. package/src/components/table/table-cell/table-cell.tsx +33 -0
  206. package/src/components/table/table-head/index.ts +1 -0
  207. package/src/components/table/table-head/table-head.tsx +29 -0
  208. package/src/components/table/table-header-cell/index.ts +1 -0
  209. package/src/components/table/table-header-cell/table-header-cell.tsx +33 -0
  210. package/src/components/table/table-row/index.ts +1 -0
  211. package/src/components/table/table-row/table-row.tsx +30 -0
  212. package/src/components/table/table.context.ts +18 -0
  213. package/src/components/table/table.styles.ts +62 -0
  214. package/src/components/table/table.test.tsx +145 -0
  215. package/src/components/table/table.tsx +91 -0
  216. package/src/components/table/table.types.ts +145 -0
  217. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,199 @@
1
+ import { useId, useUncontrolled } from "@refraktor/utils";
2
+ import { ChevronIcon } from "../../icons";
3
+ import { useTheme } from "../../theme";
4
+ import {
5
+ createClassNamesConfig,
6
+ createComponentConfig,
7
+ factory,
8
+ useClassNames,
9
+ useProps
10
+ } from "../../utils";
11
+ import { getSize } from "./breadcrumbs.styles";
12
+ import {
13
+ BreadcrumbsClassNames,
14
+ BreadcrumbsFactoryPayload,
15
+ BreadcrumbsProps
16
+ } from "./breadcrumbs.types";
17
+ import { buildBreadcrumbsRange } from "./breadcrumbs.utils";
18
+
19
+ const defaultProps = {
20
+ maxItems: 4,
21
+ itemsBeforeCollapse: 1,
22
+ itemsAfterCollapse: 1,
23
+ defaultExpanded: false,
24
+ expandLabel: "Show full breadcrumb path",
25
+ size: "md",
26
+ radius: "default"
27
+ } satisfies Partial<BreadcrumbsProps>;
28
+
29
+ const Breadcrumbs = factory<BreadcrumbsFactoryPayload>((_props, ref) => {
30
+ const { cx, getRadius } = useTheme();
31
+ const {
32
+ id,
33
+ items,
34
+ maxItems,
35
+ itemsBeforeCollapse,
36
+ itemsAfterCollapse,
37
+ expanded,
38
+ defaultExpanded,
39
+ onExpandedChange,
40
+ expandLabel,
41
+ separator,
42
+ size,
43
+ radius,
44
+ className,
45
+ classNames,
46
+ ...props
47
+ } = useProps("Breadcrumbs", defaultProps, _props);
48
+ const classes = useClassNames("Breadcrumbs", classNames);
49
+ const _id = useId(id);
50
+
51
+ const [isExpanded, setIsExpanded] = useUncontrolled<boolean>({
52
+ value: expanded,
53
+ defaultValue: defaultExpanded,
54
+ finalValue: false,
55
+ onChange: onExpandedChange
56
+ });
57
+
58
+ const sizeStyles = getSize(size);
59
+ const visibleItems = buildBreadcrumbsRange({
60
+ total: items.length,
61
+ maxItems,
62
+ itemsBeforeCollapse,
63
+ itemsAfterCollapse,
64
+ expanded: isExpanded
65
+ });
66
+
67
+ if (items.length === 0) {
68
+ return null;
69
+ }
70
+
71
+ const resolvedSeparator =
72
+ separator !== undefined ? (
73
+ separator
74
+ ) : (
75
+ <ChevronIcon direction="right" size={sizeStyles.iconSize} />
76
+ );
77
+
78
+ return (
79
+ <nav
80
+ {...props}
81
+ ref={ref}
82
+ id={_id}
83
+ aria-label={props["aria-label"] ?? "Breadcrumb"}
84
+ className={cx("w-full", classes.root, className)}
85
+ >
86
+ <ol
87
+ className={cx(
88
+ "flex flex-wrap items-center",
89
+ sizeStyles.list,
90
+ classes.list
91
+ )}
92
+ >
93
+ {visibleItems.map((rangeItem, index) => {
94
+ const showSeparator = index < visibleItems.length - 1;
95
+ const content = (() => {
96
+ if (rangeItem === "collapse") {
97
+ return (
98
+ <button
99
+ type="button"
100
+ aria-label={expandLabel}
101
+ className={cx(
102
+ "inline-flex items-center justify-center select-none outline-none transition-colors",
103
+ "focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--refraktor-primary)]",
104
+ "text-[var(--refraktor-text-secondary)] hover:bg-[var(--refraktor-bg-hover)] hover:text-[var(--refraktor-text)]",
105
+ sizeStyles.collapse,
106
+ getRadius(radius),
107
+ classes.collapse
108
+ )}
109
+ onClick={() => setIsExpanded(true)}
110
+ >
111
+ ...
112
+ </button>
113
+ );
114
+ }
115
+
116
+ const item = items[rangeItem];
117
+ const isCurrent = rangeItem === items.length - 1;
118
+ const baseLabelClass = cx(
119
+ "inline-flex min-w-0 items-center truncate",
120
+ sizeStyles.label
121
+ );
122
+
123
+ if (!isCurrent && item.href) {
124
+ return (
125
+ <a
126
+ href={item.href}
127
+ target={item.target}
128
+ rel={item.rel}
129
+ aria-label={item.ariaLabel}
130
+ className={cx(
131
+ baseLabelClass,
132
+ "outline-none transition-colors",
133
+ "focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--refraktor-primary)]",
134
+ "text-[var(--refraktor-text-secondary)] hover:text-[var(--refraktor-text)]",
135
+ classes.link
136
+ )}
137
+ >
138
+ {item.label}
139
+ </a>
140
+ );
141
+ }
142
+
143
+ return (
144
+ <span
145
+ aria-label={item.ariaLabel}
146
+ aria-current={isCurrent ? "page" : undefined}
147
+ className={cx(
148
+ baseLabelClass,
149
+ isCurrent
150
+ ? "font-medium text-[var(--refraktor-text)]"
151
+ : "text-[var(--refraktor-text-secondary)]",
152
+ isCurrent ? classes.current : classes.link
153
+ )}
154
+ >
155
+ {item.label}
156
+ </span>
157
+ );
158
+ })();
159
+
160
+ return (
161
+ <li
162
+ key={
163
+ rangeItem === "collapse"
164
+ ? "collapse"
165
+ : `item-${rangeItem}`
166
+ }
167
+ className={cx(
168
+ "inline-flex min-w-0 items-center",
169
+ sizeStyles.item,
170
+ classes.item
171
+ )}
172
+ >
173
+ {content}
174
+
175
+ {showSeparator && (
176
+ <span
177
+ aria-hidden="true"
178
+ className={cx(
179
+ "inline-flex items-center text-[var(--refraktor-text-tertiary)]",
180
+ sizeStyles.separator,
181
+ classes.separator
182
+ )}
183
+ >
184
+ {resolvedSeparator}
185
+ </span>
186
+ )}
187
+ </li>
188
+ );
189
+ })}
190
+ </ol>
191
+ </nav>
192
+ );
193
+ });
194
+
195
+ Breadcrumbs.displayName = "@refraktor/core/Breadcrumbs";
196
+ Breadcrumbs.configure = createComponentConfig<BreadcrumbsProps>();
197
+ Breadcrumbs.classNames = createClassNamesConfig<BreadcrumbsClassNames>();
198
+
199
+ export default Breadcrumbs;
@@ -0,0 +1,78 @@
1
+ import { ComponentPropsWithoutRef, ReactNode } from "react";
2
+ import { RefraktorRadius, RefraktorSize } from "../../theme";
3
+ import {
4
+ createClassNamesConfig,
5
+ createComponentConfig,
6
+ FactoryPayload
7
+ } from "../../utils";
8
+
9
+ export type BreadcrumbsItem = {
10
+ label: ReactNode;
11
+ href?: string;
12
+ target?: ComponentPropsWithoutRef<"a">["target"];
13
+ rel?: ComponentPropsWithoutRef<"a">["rel"];
14
+ ariaLabel?: string;
15
+ };
16
+
17
+ export type BreadcrumbsClassNames = {
18
+ root?: string;
19
+ list?: string;
20
+ item?: string;
21
+ link?: string;
22
+ current?: string;
23
+ separator?: string;
24
+ collapse?: string;
25
+ };
26
+
27
+ export interface BreadcrumbsProps
28
+ extends Omit<ComponentPropsWithoutRef<"nav">, "children"> {
29
+ /** Breadcrumb items in hierarchical order */
30
+ items: BreadcrumbsItem[];
31
+
32
+ /** Collapse items when amount exceeds this number. Use `0` to disable @default `4` */
33
+ maxItems?: number;
34
+
35
+ /** Amount of visible items before collapsed section @default `1` */
36
+ itemsBeforeCollapse?: number;
37
+
38
+ /** Amount of visible items after collapsed section @default `1` */
39
+ itemsAfterCollapse?: number;
40
+
41
+ /** Collapse state (controlled) */
42
+ expanded?: boolean;
43
+
44
+ /** Initial collapse state (uncontrolled) @default `false` */
45
+ defaultExpanded?: boolean;
46
+
47
+ /** Callback called when collapse state changes */
48
+ onExpandedChange?: (expanded: boolean) => void;
49
+
50
+ /** Accessible label for collapse control @default `Show full breadcrumb path` */
51
+ expandLabel?: string;
52
+
53
+ /** Separator between items */
54
+ separator?: ReactNode;
55
+
56
+ /** Size of breadcrumb text and controls @default `md` */
57
+ size?: RefraktorSize;
58
+
59
+ /** Radius of collapse control @default `default` */
60
+ radius?: RefraktorRadius;
61
+
62
+ /** Used for editing root class name */
63
+ className?: string;
64
+
65
+ /** Used for styling different parts of the component */
66
+ classNames?: BreadcrumbsClassNames;
67
+ }
68
+
69
+ export interface BreadcrumbsFactoryPayload extends FactoryPayload {
70
+ props: BreadcrumbsProps;
71
+ ref: HTMLElement;
72
+ compound: {
73
+ configure: ReturnType<typeof createComponentConfig<BreadcrumbsProps>>;
74
+ classNames: ReturnType<
75
+ typeof createClassNamesConfig<BreadcrumbsClassNames>
76
+ >;
77
+ };
78
+ }
@@ -0,0 +1,70 @@
1
+ export type BreadcrumbsRangeItem = number | "collapse";
2
+
3
+ export type BreadcrumbsRangeOptions = {
4
+ total: number;
5
+ maxItems: number;
6
+ itemsBeforeCollapse: number;
7
+ itemsAfterCollapse: number;
8
+ expanded: boolean;
9
+ };
10
+
11
+ function range(start: number, end: number) {
12
+ if (end < start) {
13
+ return [];
14
+ }
15
+
16
+ const length = end - start + 1;
17
+
18
+ return Array.from({ length }, (_, index) => start + index);
19
+ }
20
+
21
+ function toSafeInteger(value: number, fallback: number, minimum = 0) {
22
+ if (!Number.isFinite(value)) {
23
+ return fallback;
24
+ }
25
+
26
+ return Math.max(minimum, Math.trunc(value));
27
+ }
28
+
29
+ export function buildBreadcrumbsRange(
30
+ options: BreadcrumbsRangeOptions
31
+ ): BreadcrumbsRangeItem[] {
32
+ const total = toSafeInteger(options.total, 0, 0);
33
+
34
+ if (total <= 0) {
35
+ return [];
36
+ }
37
+
38
+ const all = range(0, total - 1);
39
+
40
+ if (options.expanded) {
41
+ return all;
42
+ }
43
+
44
+ const maxItems = toSafeInteger(options.maxItems, 0, 0);
45
+
46
+ if (maxItems === 0 || total <= maxItems) {
47
+ return all;
48
+ }
49
+
50
+ const itemsBeforeCollapse = Math.min(
51
+ toSafeInteger(options.itemsBeforeCollapse, 1, 1),
52
+ total - 1
53
+ );
54
+ const itemsAfterCollapse = Math.min(
55
+ toSafeInteger(options.itemsAfterCollapse, 1, 1),
56
+ total - itemsBeforeCollapse
57
+ );
58
+
59
+ const hiddenItems =
60
+ total - itemsBeforeCollapse - Math.max(itemsAfterCollapse, 1);
61
+
62
+ if (hiddenItems <= 1) {
63
+ return all;
64
+ }
65
+
66
+ const start = range(0, itemsBeforeCollapse - 1);
67
+ const end = range(total - itemsAfterCollapse, total - 1);
68
+
69
+ return [...start, "collapse", ...end];
70
+ }
@@ -0,0 +1,6 @@
1
+ export { default as Breadcrumbs } from "./breadcrumbs";
2
+ export type {
3
+ BreadcrumbsProps,
4
+ BreadcrumbsItem,
5
+ BreadcrumbsClassNames
6
+ } from "./breadcrumbs.types";
@@ -0,0 +1,43 @@
1
+ import { XIcon } from "../../../icons";
2
+ import { useTheme } from "../../../theme";
3
+ import { factory } from "../../../utils";
4
+ import { useDrawerContext } from "../drawer.context";
5
+ import { DrawerCloseFactoryPayload } from "../drawer.types";
6
+
7
+ const DrawerClose = factory<DrawerCloseFactoryPayload>(
8
+ ({ children, className, onClick, type = "button", ...props }, ref) => {
9
+ const { cx } = useTheme();
10
+ const { drawer, getStyles } = useDrawerContext();
11
+
12
+ const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
13
+ onClick?.(event);
14
+
15
+ if (event.defaultPrevented) {
16
+ return;
17
+ }
18
+
19
+ drawer.close();
20
+ };
21
+
22
+ return (
23
+ <button
24
+ ref={ref}
25
+ type={type}
26
+ aria-label="Close"
27
+ className={cx(
28
+ "size-6 cursor-pointer text-[var(--refraktor-text-secondary)] transition-colors hover:text-[var(--refraktor-text)]",
29
+ getStyles("close"),
30
+ className
31
+ )}
32
+ onClick={handleClick}
33
+ {...props}
34
+ >
35
+ {children ?? <XIcon />}
36
+ </button>
37
+ );
38
+ }
39
+ );
40
+
41
+ DrawerClose.displayName = "@refraktor/core/Drawer.Close";
42
+
43
+ export default DrawerClose;
@@ -0,0 +1 @@
1
+ export { default as DrawerClose } from "./drawer-close";
@@ -0,0 +1,98 @@
1
+ import { useTheme } from "../../../theme";
2
+ import { factory } from "../../../utils";
3
+ import { Portal } from "../../portal";
4
+ import { Transition, TransitionProps } from "../../transition";
5
+ import { useDrawerContext } from "../drawer.context";
6
+ import { DrawerContentFactoryPayload, DrawerPosition } from "../drawer.types";
7
+ import { getSizeStyles } from "../drawer.styles";
8
+
9
+ const positionClasses: Record<DrawerPosition, string> = {
10
+ left: "left-0 top-0 h-full max-h-full",
11
+ right: "right-0 top-0 h-full max-h-full",
12
+ top: "left-0 top-0 w-full max-w-full",
13
+ bottom: "bottom-0 left-0 w-full max-w-full"
14
+ };
15
+
16
+ const transitionsByPosition: Record<
17
+ DrawerPosition,
18
+ TransitionProps["transition"]
19
+ > = {
20
+ left: "slide-right",
21
+ right: "slide-left",
22
+ top: "slide-down",
23
+ bottom: "slide-up"
24
+ };
25
+
26
+ const DrawerContent = factory<DrawerContentFactoryPayload>(
27
+ ({ children, className, style, ...props }, ref) => {
28
+ const { cx, getRadius } = useTheme();
29
+ const {
30
+ drawer,
31
+ withinPortal,
32
+ radius,
33
+ position,
34
+ size,
35
+ transitionProps,
36
+ headerId,
37
+ contentRef,
38
+ getStyles
39
+ } = useDrawerContext();
40
+
41
+ const setRefs = (node: HTMLDivElement | null) => {
42
+ contentRef.current = node;
43
+
44
+ if (typeof ref === "function") {
45
+ ref(node);
46
+ } else if (ref) {
47
+ ref.current = node;
48
+ }
49
+ };
50
+
51
+ const { className: transitionClassName, ...resolvedTransitionProps } =
52
+ transitionProps ?? {};
53
+
54
+ const sizeStyles = getSizeStyles(position, size);
55
+
56
+ const content = (
57
+ <Transition
58
+ transition={transitionsByPosition[position]}
59
+ duration={200}
60
+ mounted={drawer.opened}
61
+ {...resolvedTransitionProps}
62
+ className={cx(
63
+ "fixed inset-0 z-50 pointer-events-none",
64
+ transitionClassName
65
+ )}
66
+ >
67
+ <div
68
+ ref={setRefs}
69
+ role="dialog"
70
+ aria-modal="true"
71
+ aria-labelledby={headerId}
72
+ data-opened={drawer.opened}
73
+ data-position={position}
74
+ style={{
75
+ ...sizeStyles,
76
+ ...style
77
+ }}
78
+ className={cx(
79
+ "pointer-events-auto fixed z-50 border border-[var(--refraktor-border)] bg-[var(--refraktor-bg)] p-4 text-[var(--refraktor-text)] shadow-md",
80
+ positionClasses[position],
81
+ getRadius(radius),
82
+ getStyles("content"),
83
+ className
84
+ )}
85
+ {...props}
86
+ >
87
+ {children}
88
+ </div>
89
+ </Transition>
90
+ );
91
+
92
+ return withinPortal ? <Portal>{content}</Portal> : content;
93
+ }
94
+ );
95
+
96
+ DrawerContent.displayName = "@refraktor/core/Drawer.Content";
97
+
98
+ export default DrawerContent;
@@ -0,0 +1 @@
1
+ export { default as DrawerContent } from "./drawer-content";
@@ -0,0 +1,40 @@
1
+ import { useTheme } from "../../../theme";
2
+ import { factory } from "../../../utils";
3
+ import { DrawerClose } from "../drawer-close";
4
+ import { useDrawerContext } from "../drawer.context";
5
+ import { DrawerHeaderFactoryPayload } from "../drawer.types";
6
+
7
+ const DrawerHeader = factory<DrawerHeaderFactoryPayload>(
8
+ ({ children, className, id, text, withClose = true, ...props }, ref) => {
9
+ const { cx } = useTheme();
10
+ const { headerId, getStyles } = useDrawerContext();
11
+ const resolvedId = id ?? headerId;
12
+
13
+ return (
14
+ <div
15
+ ref={ref}
16
+ className={cx(
17
+ "mb-4 flex items-center justify-between",
18
+ getStyles("header"),
19
+ className
20
+ )}
21
+ {...props}
22
+ >
23
+ <div
24
+ id={resolvedId}
25
+ className="min-w-0 flex-1 text-sm font-semibold leading-5 text-[var(--refraktor-text)]"
26
+ >
27
+ {text ?? children}
28
+ </div>
29
+
30
+ {withClose && (
31
+ <DrawerClose className="static shrink-0 self-center" />
32
+ )}
33
+ </div>
34
+ );
35
+ }
36
+ );
37
+
38
+ DrawerHeader.displayName = "@refraktor/core/Drawer.Header";
39
+
40
+ export default DrawerHeader;
@@ -0,0 +1 @@
1
+ export { default as DrawerHeader } from "./drawer-header";
@@ -0,0 +1,86 @@
1
+ import { useTheme } from "../../../theme";
2
+ import { factory } from "../../../utils";
3
+ import { Portal } from "../../portal";
4
+ import { Transition } from "../../transition";
5
+ import { useDrawerContext } from "../drawer.context";
6
+ import { DrawerOverlayFactoryPayload } from "../drawer.types";
7
+
8
+ const DrawerOverlay = factory<DrawerOverlayFactoryPayload>(
9
+ (
10
+ {
11
+ closeOnClick = true,
12
+ backgroundOpacity = 0.5,
13
+ blur = 0,
14
+ className,
15
+ onMouseDown,
16
+ style,
17
+ ...props
18
+ },
19
+ ref
20
+ ) => {
21
+ const { cx } = useTheme();
22
+ const {
23
+ drawer,
24
+ closeOnClickOutside,
25
+ withinPortal,
26
+ transitionProps,
27
+ getStyles
28
+ } = useDrawerContext();
29
+
30
+ const blurValue = typeof blur === "number" ? `${blur}px` : blur;
31
+ const backdropFilterValue =
32
+ blurValue !== "0" && blurValue !== "0px"
33
+ ? `blur(${blurValue})`
34
+ : undefined;
35
+
36
+ const handleMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {
37
+ onMouseDown?.(event);
38
+
39
+ if (
40
+ event.defaultPrevented ||
41
+ !closeOnClick ||
42
+ !closeOnClickOutside
43
+ ) {
44
+ return;
45
+ }
46
+
47
+ drawer.close();
48
+ };
49
+
50
+ const overlayContent = (
51
+ <Transition
52
+ transition="fade"
53
+ duration={150}
54
+ mounted={drawer.opened}
55
+ {...transitionProps}
56
+ >
57
+ <div
58
+ ref={ref}
59
+ aria-hidden="true"
60
+ className={cx(
61
+ "fixed inset-0 z-40",
62
+ getStyles("overlay"),
63
+ className
64
+ )}
65
+ style={{
66
+ backgroundColor: `rgba(0, 0, 0, ${backgroundOpacity})`,
67
+ backdropFilter: backdropFilterValue,
68
+ ...style
69
+ }}
70
+ onMouseDown={handleMouseDown}
71
+ {...props}
72
+ />
73
+ </Transition>
74
+ );
75
+
76
+ return withinPortal ? (
77
+ <Portal>{overlayContent}</Portal>
78
+ ) : (
79
+ overlayContent
80
+ );
81
+ }
82
+ );
83
+
84
+ DrawerOverlay.displayName = "@refraktor/core/Drawer.Overlay";
85
+
86
+ export default DrawerOverlay;
@@ -0,0 +1 @@
1
+ export { default as DrawerOverlay } from "./drawer-overlay";