@heymantle/litho 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -0
- package/dist/cjs/components/Card.js +1 -1
- package/dist/cjs/components/Disclosure.js +46 -15
- package/dist/cjs/components/DropZone.js +89 -37
- package/dist/cjs/components/Layout.js +4 -2
- package/dist/cjs/components/Modal.js +14 -3
- package/dist/cjs/components/Popover.js +26 -9
- package/dist/cjs/components/Table.js +27 -11
- package/dist/cjs/components/Tabs.js +33 -2
- package/dist/cjs/playwright.config.js +114 -0
- package/dist/cjs/styles/Table.js +2 -7
- package/dist/cjs/tests/visual/stories.spec.js +637 -0
- package/dist/cjs/utilities/dates.js +7 -7
- package/dist/esm/components/Card.js +1 -1
- package/dist/esm/components/Disclosure.js +36 -5
- package/dist/esm/components/DropZone.js +89 -37
- package/dist/esm/components/Layout.js +4 -2
- package/dist/esm/components/Modal.js +14 -3
- package/dist/esm/components/Popover.js +26 -9
- package/dist/esm/components/Table.js +27 -11
- package/dist/esm/components/Tabs.js +33 -2
- package/dist/esm/playwright.config.js +104 -0
- package/dist/esm/styles/Table.js +2 -7
- package/dist/esm/tests/visual/stories.spec.js +633 -0
- package/dist/esm/utilities/dates.js +7 -7
- package/dist/types/components/Disclosure.d.ts.map +1 -1
- package/dist/types/components/DropZone.d.ts +2 -0
- package/dist/types/components/DropZone.d.ts.map +1 -1
- package/dist/types/components/Layout.d.ts.map +1 -1
- package/dist/types/components/Modal.d.ts.map +1 -1
- package/dist/types/components/Popover.d.ts +2 -0
- package/dist/types/components/Popover.d.ts.map +1 -1
- package/dist/types/components/Table.d.ts.map +1 -1
- package/dist/types/components/Tabs.d.ts +45 -1
- package/dist/types/components/Tabs.d.ts.map +1 -1
- package/dist/types/styles/Table.d.ts.map +1 -1
- package/package.json +12 -3
package/README.md
CHANGED
|
@@ -107,6 +107,58 @@ Build a customer list page with search and filtering using Litho components.
|
|
|
107
107
|
|
|
108
108
|
See **`AI_USAGE_IN_PROJECTS.md`** for detailed instructions on accessing guides and Storybook examples from projects using Litho as a dependency.
|
|
109
109
|
|
|
110
|
+
## Visual Regression Testing
|
|
111
|
+
|
|
112
|
+
Litho includes automated visual regression tests using Playwright to catch unintended UI changes.
|
|
113
|
+
|
|
114
|
+
### Running Tests
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Run visual regression tests (uses Docker for CI parity)
|
|
118
|
+
npm run test:visual:docker
|
|
119
|
+
|
|
120
|
+
# Update baseline screenshots (uses Docker for CI parity)
|
|
121
|
+
npm run test:visual:docker:update
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
> **Note:** The Docker commands ensure baselines match CI exactly. Native commands (`npm run test:visual`) are also available but may produce different results due to font rendering differences between macOS and Linux.
|
|
125
|
+
|
|
126
|
+
### When Baselines Need Updating
|
|
127
|
+
|
|
128
|
+
Update baselines when you've made **intentional** visual changes:
|
|
129
|
+
- Modified component styles or layout
|
|
130
|
+
- Changed default props or variants
|
|
131
|
+
- Updated theme colors or typography
|
|
132
|
+
- Added new visual states to existing components
|
|
133
|
+
|
|
134
|
+
### Adding New Stories
|
|
135
|
+
|
|
136
|
+
When you add a new component or story:
|
|
137
|
+
1. The visual tests automatically discover all stories from Storybook
|
|
138
|
+
2. Run `npm run test:visual:update` to generate baseline screenshots for new stories
|
|
139
|
+
3. Commit the new baseline images in `tests/visual/stories.spec.js-snapshots/`
|
|
140
|
+
|
|
141
|
+
### Skipped Stories
|
|
142
|
+
|
|
143
|
+
Some stories are skipped because they contain non-deterministic content:
|
|
144
|
+
- **Image stories** - Use random external images from picsum.photos
|
|
145
|
+
- Add problematic stories to `SKIP_STORIES` in `tests/visual/stories.spec.js`
|
|
146
|
+
|
|
147
|
+
### CI Integration
|
|
148
|
+
|
|
149
|
+
Visual tests run automatically on PRs to `main`. If tests fail:
|
|
150
|
+
1. Download the `visual-regression-diffs` artifact from the workflow
|
|
151
|
+
2. Review the diff images to determine if changes are intentional
|
|
152
|
+
3. If intentional, use the **Update Visual Baselines** workflow to regenerate baselines
|
|
153
|
+
|
|
154
|
+
### Generating Baselines from CI
|
|
155
|
+
|
|
156
|
+
Since macOS and Linux render fonts differently, generate baselines from CI for best results:
|
|
157
|
+
|
|
158
|
+
1. Go to **Actions** → **Update Visual Baselines** → **Run workflow**
|
|
159
|
+
2. The workflow will create a PR with updated baselines
|
|
160
|
+
3. Review and merge the PR
|
|
161
|
+
|
|
110
162
|
## License
|
|
111
163
|
|
|
112
164
|
MIT
|
|
@@ -516,7 +516,7 @@ var sectionBodyStyles = (0, _tailwindvariants.tv)({
|
|
|
516
516
|
};
|
|
517
517
|
Card.Section.displayName = "Card.Section";
|
|
518
518
|
var clickableRowStyles = (0, _tailwindvariants.tv)({
|
|
519
|
-
base: "Litho-Card__Row py-1.5 px-2.5 cursor-pointer rounded-md hover:bg-tint-2 active:bg-tint-3",
|
|
519
|
+
base: "Litho-Card__Row py-1.5 px-2.5 @md:px-3 cursor-pointer rounded-md hover:bg-tint-2 active:bg-tint-3",
|
|
520
520
|
variants: {
|
|
521
521
|
disabled: {
|
|
522
522
|
true: "opacity-50 cursor-not-allowed pointer-events-none"
|
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "default", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return _default;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
var _jsxruntime = require("react/jsx-runtime");
|
|
12
|
+
var _tailwindvariants = require("tailwind-variants");
|
|
13
|
+
var styles = (0, _tailwindvariants.tv)({
|
|
14
|
+
base: "Litho-Disclosure relative",
|
|
15
|
+
variants: {
|
|
16
|
+
flush: {
|
|
17
|
+
true: "pl-4",
|
|
18
|
+
false: "pl-7.5 @md:pl-7"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: {
|
|
22
|
+
flush: false
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
var borderStyles = (0, _tailwindvariants.tv)({
|
|
26
|
+
base: "Litho-Disclosure__Border absolute top-0 w-px h-full bg-tint-5 dark:bg-tint-alt-5",
|
|
27
|
+
variants: {
|
|
28
|
+
flush: {
|
|
29
|
+
true: "left-0.5",
|
|
30
|
+
false: "left-[9px]"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
defaultVariants: {
|
|
34
|
+
flush: false
|
|
35
|
+
}
|
|
36
|
+
});
|
|
1
37
|
/**
|
|
2
38
|
* Renders a Disclosure component that displays content with disclosure styling.
|
|
3
39
|
*
|
|
@@ -18,25 +54,20 @@
|
|
|
18
54
|
* <Disclosure className="mt-4">
|
|
19
55
|
* <Text>This is disclosure content with margin</Text>
|
|
20
56
|
* </Disclosure>
|
|
21
|
-
*/
|
|
22
|
-
Object.defineProperty(exports, "__esModule", {
|
|
23
|
-
value: true
|
|
24
|
-
});
|
|
25
|
-
Object.defineProperty(exports, "default", {
|
|
26
|
-
enumerable: true,
|
|
27
|
-
get: function() {
|
|
28
|
-
return _default;
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
var _jsxruntime = require("react/jsx-runtime");
|
|
32
|
-
function Disclosure() {
|
|
57
|
+
*/ function Disclosure() {
|
|
33
58
|
var props = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
34
|
-
var children = props.children, className = props.className;
|
|
59
|
+
var children = props.children, className = props.className, _props_flush = props.flush, flush = _props_flush === void 0 ? false : _props_flush;
|
|
60
|
+
var classes = styles({
|
|
61
|
+
flush: flush
|
|
62
|
+
});
|
|
63
|
+
var borderClasses = borderStyles({
|
|
64
|
+
flush: flush
|
|
65
|
+
});
|
|
35
66
|
return /*#__PURE__*/ (0, _jsxruntime.jsxs)("div", {
|
|
36
|
-
className: "
|
|
67
|
+
className: "".concat(classes).concat(className ? " ".concat(className) : ""),
|
|
37
68
|
children: [
|
|
38
69
|
/*#__PURE__*/ (0, _jsxruntime.jsx)("div", {
|
|
39
|
-
className:
|
|
70
|
+
className: borderClasses
|
|
40
71
|
}),
|
|
41
72
|
/*#__PURE__*/ (0, _jsxruntime.jsx)("div", {
|
|
42
73
|
children: children
|
|
@@ -84,6 +84,42 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
84
84
|
if (n === "Map" || n === "Set") return Array.from(n);
|
|
85
85
|
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
86
86
|
}
|
|
87
|
+
var normalizeDropZoneAccept = function(accept) {
|
|
88
|
+
if (!accept) return [];
|
|
89
|
+
return typeof accept === "string" ? [
|
|
90
|
+
accept
|
|
91
|
+
] : accept;
|
|
92
|
+
};
|
|
93
|
+
var isFileAcceptedForDropZone = function(file) {
|
|
94
|
+
var accept = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : [];
|
|
95
|
+
if (!accept || accept.length === 0) return true;
|
|
96
|
+
return accept.some(function(type) {
|
|
97
|
+
if (!type) return false;
|
|
98
|
+
if (type === "*/*") return true;
|
|
99
|
+
if (type.endsWith("/*")) {
|
|
100
|
+
var _type_split = _sliced_to_array(type.split("/"), 1), prefix = _type_split[0];
|
|
101
|
+
if (prefix === "*") return true;
|
|
102
|
+
return !!(file === null || file === void 0 ? void 0 : file.type) && file.type.startsWith("".concat(prefix, "/"));
|
|
103
|
+
}
|
|
104
|
+
return (file === null || file === void 0 ? void 0 : file.type) === type;
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
var partitionFilesByDropZoneAccept = function(files) {
|
|
108
|
+
var accept = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : [];
|
|
109
|
+
var acceptedFiles = [];
|
|
110
|
+
var rejectedFiles = [];
|
|
111
|
+
files.forEach(function(file) {
|
|
112
|
+
if (isFileAcceptedForDropZone(file, accept)) {
|
|
113
|
+
acceptedFiles.push(file);
|
|
114
|
+
} else {
|
|
115
|
+
rejectedFiles.push(file);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
acceptedFiles: acceptedFiles,
|
|
120
|
+
rejectedFiles: rejectedFiles
|
|
121
|
+
};
|
|
122
|
+
};
|
|
87
123
|
var dropZoneStyles = (0, _tailwindvariants.tv)({
|
|
88
124
|
base: "Litho-DropZone w-full flex items-center justify-center p-4 border border-form-border border-dashed rounded-md focus:outline-hidden",
|
|
89
125
|
variants: {
|
|
@@ -145,11 +181,7 @@ var dropZoneStyles = (0, _tailwindvariants.tv)({
|
|
|
145
181
|
*/ function DropZone() {
|
|
146
182
|
var props = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
147
183
|
var id = props.id, label = props.label, labelHidden = props.labelHidden, labelAction = props.labelAction, tooltip = props.tooltip, labelVariant = props.labelVariant, _props_type = props.type, type = _props_type === void 0 ? "file" : _props_type, _accept = props.accept, _props_allowMultiple = props.allowMultiple, allowMultiple = _props_allowMultiple === void 0 ? false : _props_allowMultiple, _props_showDropZoneWhenDisabled = props.showDropZoneWhenDisabled, showDropZoneWhenDisabled = _props_showDropZoneWhenDisabled === void 0 ? true : _props_showDropZoneWhenDisabled, _disabled = props.disabled, onDrop = props.onDrop, onDropAccepted = props.onDropAccepted, onDropRejected = props.onDropRejected, helpText = props.helpText, error = props.error, _props_uploading = props.uploading, uploading = _props_uploading === void 0 ? false : _props_uploading, _props_uploadedFiles = props.uploadedFiles, uploadedFiles = _props_uploadedFiles === void 0 ? [] : _props_uploadedFiles, _props_uploadLabel = props.uploadLabel, uploadLabel = _props_uploadLabel === void 0 ? "Drag and drop files or click to upload" : _props_uploadLabel, _props_uploadingLabel = props.uploadingLabel, uploadingLabel = _props_uploadingLabel === void 0 ? "Uploading..." : _props_uploadingLabel, _props_dragLabel = props.dragLabel, dragLabel = _props_dragLabel === void 0 ? "Release to upload" : _props_dragLabel, tmp = props.showFilePreview, _showFilePreview = tmp === void 0 ? true : tmp, previewLoading = props.previewLoading, _props_previewRows = props.previewRows, previewRows = _props_previewRows === void 0 ? 2 : _props_previewRows, onRemove = props.onRemove, onFilePreviewClick = props.onFilePreviewClick, filename = props.filename;
|
|
148
|
-
var accept = _accept
|
|
149
|
-
_accept
|
|
150
|
-
] : _accept : [
|
|
151
|
-
"*/*"
|
|
152
|
-
];
|
|
184
|
+
var accept = normalizeDropZoneAccept(_accept);
|
|
153
185
|
var inputRef = (0, _react.useRef)(null);
|
|
154
186
|
var _useState = _sliced_to_array((0, _react.useState)(false), 2), hasFocusWithin = _useState[0], setHasFocusWithin = _useState[1];
|
|
155
187
|
var _useState1 = _sliced_to_array((0, _react.useState)(false), 2), isDraggingOver = _useState1[0], setIsDraggingOver = _useState1[1];
|
|
@@ -210,22 +242,7 @@ var dropZoneStyles = (0, _tailwindvariants.tv)({
|
|
|
210
242
|
setDragFileCount(0);
|
|
211
243
|
if (disabled) return;
|
|
212
244
|
var droppedFiles = Array.from(event.dataTransfer.files);
|
|
213
|
-
var acceptedFiles =
|
|
214
|
-
var rejectedFiles = [];
|
|
215
|
-
droppedFiles.forEach(function(file) {
|
|
216
|
-
var isValidType = typeAccept.length === 0 || typeAccept.some(function(type) {
|
|
217
|
-
if (type.endsWith("/*")) {
|
|
218
|
-
return file.type.startsWith("".concat(type.split("/")[0], "/"));
|
|
219
|
-
}
|
|
220
|
-
return file.type === type;
|
|
221
|
-
});
|
|
222
|
-
var isValid = isValidType;
|
|
223
|
-
if (isValid) {
|
|
224
|
-
acceptedFiles.push(file);
|
|
225
|
-
} else {
|
|
226
|
-
rejectedFiles.push(file);
|
|
227
|
-
}
|
|
228
|
-
});
|
|
245
|
+
var _partitionFilesByDropZoneAccept = partitionFilesByDropZoneAccept(droppedFiles, typeAccept), acceptedFiles = _partitionFilesByDropZoneAccept.acceptedFiles, rejectedFiles = _partitionFilesByDropZoneAccept.rejectedFiles;
|
|
229
246
|
if (onDrop) {
|
|
230
247
|
onDrop(droppedFiles);
|
|
231
248
|
}
|
|
@@ -238,22 +255,7 @@ var dropZoneStyles = (0, _tailwindvariants.tv)({
|
|
|
238
255
|
};
|
|
239
256
|
var handleFileChange = function(event) {
|
|
240
257
|
var selectedFiles = Array.from(event.target.files);
|
|
241
|
-
var acceptedFiles =
|
|
242
|
-
var rejectedFiles = [];
|
|
243
|
-
selectedFiles.forEach(function(file) {
|
|
244
|
-
var isValidType = typeAccept.length === 0 || typeAccept.some(function(type) {
|
|
245
|
-
if (type.endsWith("/*")) {
|
|
246
|
-
return file.type.startsWith("".concat(type.split("/")[0], "/"));
|
|
247
|
-
}
|
|
248
|
-
return file.type === type;
|
|
249
|
-
});
|
|
250
|
-
var isValid = isValidType;
|
|
251
|
-
if (isValid) {
|
|
252
|
-
acceptedFiles.push(file);
|
|
253
|
-
} else {
|
|
254
|
-
rejectedFiles.push(file);
|
|
255
|
-
}
|
|
256
|
-
});
|
|
258
|
+
var _partitionFilesByDropZoneAccept = partitionFilesByDropZoneAccept(selectedFiles, typeAccept), acceptedFiles = _partitionFilesByDropZoneAccept.acceptedFiles, rejectedFiles = _partitionFilesByDropZoneAccept.rejectedFiles;
|
|
257
259
|
if (onDrop) {
|
|
258
260
|
onDrop(selectedFiles);
|
|
259
261
|
}
|
|
@@ -373,6 +375,56 @@ var dropZoneStyles = (0, _tailwindvariants.tv)({
|
|
|
373
375
|
]
|
|
374
376
|
});
|
|
375
377
|
}
|
|
378
|
+
var DropTarget = function() {
|
|
379
|
+
var props = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
380
|
+
var _accept = props.accept, _props_allowMultiple = props.allowMultiple, allowMultiple = _props_allowMultiple === void 0 ? true : _props_allowMultiple, _props_disabled = props.disabled, disabled = _props_disabled === void 0 ? false : _props_disabled, onDrop = props.onDrop, onDropAccepted = props.onDropAccepted, onDropRejected = props.onDropRejected, className = props.className, dragOverClassName = props.dragOverClassName, children = props.children;
|
|
381
|
+
var accept = normalizeDropZoneAccept(_accept);
|
|
382
|
+
var _useState = _sliced_to_array((0, _react.useState)(false), 2), isDraggingOver = _useState[0], setIsDraggingOver = _useState[1];
|
|
383
|
+
var handleDragOver = function(event) {
|
|
384
|
+
event.preventDefault();
|
|
385
|
+
event.stopPropagation();
|
|
386
|
+
if (!disabled) {
|
|
387
|
+
setIsDraggingOver(true);
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
var handleDragLeave = function(event) {
|
|
391
|
+
event.preventDefault();
|
|
392
|
+
event.stopPropagation();
|
|
393
|
+
setIsDraggingOver(false);
|
|
394
|
+
};
|
|
395
|
+
var handleDrop = function(event) {
|
|
396
|
+
event.preventDefault();
|
|
397
|
+
event.stopPropagation();
|
|
398
|
+
setIsDraggingOver(false);
|
|
399
|
+
if (disabled) return;
|
|
400
|
+
var droppedFiles = Array.from(event.dataTransfer.files);
|
|
401
|
+
if (allowMultiple === false) {
|
|
402
|
+
droppedFiles = droppedFiles.slice(0, 1);
|
|
403
|
+
}
|
|
404
|
+
var _partitionFilesByDropZoneAccept = partitionFilesByDropZoneAccept(droppedFiles, accept), acceptedFiles = _partitionFilesByDropZoneAccept.acceptedFiles, rejectedFiles = _partitionFilesByDropZoneAccept.rejectedFiles;
|
|
405
|
+
if (onDrop) {
|
|
406
|
+
onDrop(droppedFiles);
|
|
407
|
+
}
|
|
408
|
+
if (onDropAccepted && acceptedFiles.length > 0) {
|
|
409
|
+
onDropAccepted(acceptedFiles);
|
|
410
|
+
}
|
|
411
|
+
if (onDropRejected && rejectedFiles.length > 0) {
|
|
412
|
+
onDropRejected(rejectedFiles);
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
var dropTargetClassName = [
|
|
416
|
+
className,
|
|
417
|
+
isDraggingOver && dragOverClassName
|
|
418
|
+
].filter(Boolean).join(" ");
|
|
419
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsx)("div", {
|
|
420
|
+
className: dropTargetClassName,
|
|
421
|
+
onDragOver: handleDragOver,
|
|
422
|
+
onDragLeave: handleDragLeave,
|
|
423
|
+
onDrop: handleDrop,
|
|
424
|
+
children: children
|
|
425
|
+
});
|
|
426
|
+
};
|
|
427
|
+
DropZone.DropTarget = DropTarget;
|
|
376
428
|
var previewContainerStyles = (0, _tailwindvariants.tv)({
|
|
377
429
|
base: "flex flex-col",
|
|
378
430
|
variants: {
|
|
@@ -211,11 +211,13 @@ var annotatedSectionStyles = (0, _tailwindvariants.tv)({
|
|
|
211
211
|
var annotatedSectionClasses = annotatedSectionStyles({
|
|
212
212
|
embedded: embedded
|
|
213
213
|
});
|
|
214
|
+
var annotationColSpan = embedded ? "@md-embed:col-span-4" : "@md:col-span-4";
|
|
215
|
+
var contentColSpan = embedded ? "@md-embed:col-span-8" : "@md:col-span-8";
|
|
214
216
|
return /*#__PURE__*/ (0, _jsxruntime.jsxs)("div", {
|
|
215
217
|
className: annotatedSectionClasses,
|
|
216
218
|
children: [
|
|
217
219
|
/*#__PURE__*/ (0, _jsxruntime.jsxs)("div", {
|
|
218
|
-
className: "Litho-Layout__Annotation flex flex-col gap-1
|
|
220
|
+
className: "Litho-Layout__Annotation flex flex-col gap-1 ".concat(annotationColSpan, " py-2"),
|
|
219
221
|
children: [
|
|
220
222
|
title && (typeof title === "string" ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_Text.default, {
|
|
221
223
|
variant: "headingMd",
|
|
@@ -228,7 +230,7 @@ var annotatedSectionStyles = (0, _tailwindvariants.tv)({
|
|
|
228
230
|
]
|
|
229
231
|
}),
|
|
230
232
|
/*#__PURE__*/ (0, _jsxruntime.jsx)("div", {
|
|
231
|
-
className: "Litho-Layout__AnnotationContent
|
|
233
|
+
className: "Litho-Layout__AnnotationContent ".concat(contentColSpan),
|
|
232
234
|
children: children
|
|
233
235
|
})
|
|
234
236
|
]
|
|
@@ -127,7 +127,16 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
127
127
|
}
|
|
128
128
|
var ModalContext = /*#__PURE__*/ (0, _react.createContext)(false);
|
|
129
129
|
var containerStyles = (0, _tailwindvariants.tv)({
|
|
130
|
-
base: "Litho-ModalContainer fixed inset-0 block flex flex-col justify-end md:justify-center items-center pointer-events-none"
|
|
130
|
+
base: "Litho-ModalContainer fixed inset-0 block flex flex-col justify-end md:justify-center items-center pointer-events-none",
|
|
131
|
+
variants: {
|
|
132
|
+
hidden: {
|
|
133
|
+
true: "hidden opacity-0 pointer-events-none",
|
|
134
|
+
false: ""
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
defaultVariants: {
|
|
138
|
+
hidden: false
|
|
139
|
+
}
|
|
131
140
|
});
|
|
132
141
|
var styles = (0, _tailwindvariants.tv)({
|
|
133
142
|
base: "Litho-Modal relative bg-surface-highest shadow-modal dark:shadow-modal-dark w-full mx-auto pointer-events-auto flex flex-col overflow-hidden",
|
|
@@ -206,7 +215,7 @@ var sectionStyles = (0, _tailwindvariants.tv)({
|
|
|
206
215
|
* @returns {React.ReactPortal|null} The rendered modal component or null if not open.
|
|
207
216
|
*/ function Modal() {
|
|
208
217
|
var props = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
209
|
-
var children = props.children, title = props.title, subtitle = props.subtitle, open = props.open, onClose = props.onClose, sectioned = props.sectioned, primaryAction = props.primaryAction, secondaryAction = props.secondaryAction, _props_secondaryActions = props.secondaryActions, secondaryActions = _props_secondaryActions === void 0 ? [] : _props_secondaryActions, destructiveAction = props.destructiveAction, loading = props.loading, _props_size = props.size, size = _props_size === void 0 ? "default" : _props_size, leftAccessory = props.leftAccessory, _props_hideCloseButton = props.hideCloseButton, hideCloseButton = _props_hideCloseButton === void 0 ? false : _props_hideCloseButton, backAction = props.backAction, zIndexOverride = props.zIndexOverride, _props_autoFocusFirstInput = props.autoFocusFirstInput, autoFocusFirstInput = _props_autoFocusFirstInput === void 0 ? true : _props_autoFocusFirstInput, bodyClassName = props.bodyClassName;
|
|
218
|
+
var children = props.children, title = props.title, subtitle = props.subtitle, open = props.open, _props_hidden = props.hidden, hidden = _props_hidden === void 0 ? false : _props_hidden, onClose = props.onClose, sectioned = props.sectioned, primaryAction = props.primaryAction, secondaryAction = props.secondaryAction, _props_secondaryActions = props.secondaryActions, secondaryActions = _props_secondaryActions === void 0 ? [] : _props_secondaryActions, destructiveAction = props.destructiveAction, loading = props.loading, _props_size = props.size, size = _props_size === void 0 ? "default" : _props_size, leftAccessory = props.leftAccessory, _props_hideCloseButton = props.hideCloseButton, hideCloseButton = _props_hideCloseButton === void 0 ? false : _props_hideCloseButton, backAction = props.backAction, zIndexOverride = props.zIndexOverride, _props_autoFocusFirstInput = props.autoFocusFirstInput, autoFocusFirstInput = _props_autoFocusFirstInput === void 0 ? true : _props_autoFocusFirstInput, bodyClassName = props.bodyClassName;
|
|
210
219
|
var setModalIsOpen = (0, _Frame.useFrame)().setModalIsOpen;
|
|
211
220
|
var modalContentRef = (0, _react.useRef)(null);
|
|
212
221
|
var hasChildren = !!children;
|
|
@@ -214,7 +223,9 @@ var sectionStyles = (0, _tailwindvariants.tv)({
|
|
|
214
223
|
sectioned: sectioned,
|
|
215
224
|
size: size
|
|
216
225
|
});
|
|
217
|
-
var containerClasses = containerStyles(
|
|
226
|
+
var containerClasses = containerStyles({
|
|
227
|
+
hidden: hidden
|
|
228
|
+
});
|
|
218
229
|
var headerClasses = headerStyles({
|
|
219
230
|
hasChildren: hasChildren
|
|
220
231
|
});
|
|
@@ -189,18 +189,23 @@ var styles = (0, _tailwindvariants.tv)({
|
|
|
189
189
|
* @param {boolean} [props.sectioned=false] - Whether the popover content is sectioned with padding.
|
|
190
190
|
* @param {string} [props.preferredAlignment="center"] - Preferred alignment for the popover (left, center, right).
|
|
191
191
|
* @param {string} [props.preferredPosition="below"] - Preferred position for the popover (above, below, cover, left, right).
|
|
192
|
+
* @param {number} [props.horizontalOffset] - Custom horizontal offset in pixels to adjust the popover position.
|
|
192
193
|
* @param {string} [props.className] - Additional class name for the popover.
|
|
193
194
|
* @param {string} [props.containerClassName] - Additional class name for the popover container.
|
|
194
195
|
* @returns {JSX.Element} The rendered popover component.
|
|
195
196
|
*/ function Popover() {
|
|
196
197
|
var props = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
197
|
-
var activatorWrapper = props.activatorWrapper, _props_activatorDisplayType = props.activatorDisplayType, activatorDisplayType = _props_activatorDisplayType === void 0 ? "inline-block" : _props_activatorDisplayType, activator = props.activator, children = props.children, onClose = props.onClose,
|
|
198
|
+
var activatorWrapper = props.activatorWrapper, _props_activatorDisplayType = props.activatorDisplayType, activatorDisplayType = _props_activatorDisplayType === void 0 ? "inline-block" : _props_activatorDisplayType, activator = props.activator, children = props.children, onClose = props.onClose, activeProp = props.active, fixed = props.fixed, zIndexOverride = props.zIndexOverride, _props_sectioned = props.sectioned, sectioned = _props_sectioned === void 0 ? false : _props_sectioned, _props_preferredAlignment = props.preferredAlignment, preferredAlignment = _props_preferredAlignment === void 0 ? "center" : _props_preferredAlignment, _props_preferredPosition = props.preferredPosition, preferredPosition = _props_preferredPosition === void 0 ? "below" : _props_preferredPosition, _props_horizontalOffset = props.horizontalOffset, horizontalOffset = _props_horizontalOffset === void 0 ? 0 : _props_horizontalOffset, _props_matchActivatorWidth = props.matchActivatorWidth, matchActivatorWidth = _props_matchActivatorWidth === void 0 ? false : _props_matchActivatorWidth, _props_maxWidth = props.maxWidth, maxWidth = _props_maxWidth === void 0 ? "default" : _props_maxWidth, className = props.className, containerClassName = props.containerClassName, _props_closeOnResize = props.closeOnResize, closeOnResize = _props_closeOnResize === void 0 ? true : _props_closeOnResize, _props_debounceResizeObserver = props.debounceResizeObserver, debounceResizeObserver = _props_debounceResizeObserver === void 0 ? false : _props_debounceResizeObserver, _props_usePortal = props.usePortal, usePortal = _props_usePortal === void 0 ? true : _props_usePortal;
|
|
198
199
|
var ActivatorWrapper = activatorWrapper || "div";
|
|
199
200
|
var idValue = (0, _react.useId)();
|
|
200
201
|
var idRef = (0, _react.useRef)(idValue);
|
|
201
202
|
var initialWidthRef = (0, _react.useRef)(null);
|
|
202
203
|
var popoverRef = (0, _react.useRef)(null);
|
|
203
204
|
var activatorRef = (0, _react.useRef)(null);
|
|
205
|
+
// Check if the activator is inside an inert element (e.g., table cells covered by fixed columns)
|
|
206
|
+
var isActivatorInert = activatorRef.current ? activatorRef.current.closest('[inert]') !== null : false;
|
|
207
|
+
// When disabled, prevent popover from opening
|
|
208
|
+
var active = isActivatorInert ? false : activeProp;
|
|
204
209
|
var _useState = _sliced_to_array((0, _react.useState)(_object_spread({
|
|
205
210
|
visibility: "hidden",
|
|
206
211
|
opacity: 0,
|
|
@@ -283,7 +288,7 @@ var styles = (0, _tailwindvariants.tv)({
|
|
|
283
288
|
} else if (preferredAlignment === "right") {
|
|
284
289
|
left = fixed ? activatorRect.right - popoverRect.width : activatorRect.right + window.scrollX - popoverRect.width;
|
|
285
290
|
} else if (preferredAlignment === "center") {
|
|
286
|
-
left = fixed ? activatorRect.left + activatorRect.width / 2 - popoverRect.width / 2 : activatorRect.left + window.scrollX + activatorRect.width / 2 - popoverRect.width / 2;
|
|
291
|
+
left = fixed ? activatorRect.left + activatorRect.width / 2 - popoverRect.width / 2 + horizontalOffset : activatorRect.left + window.scrollX + activatorRect.width / 2 - popoverRect.width / 2 + horizontalOffset;
|
|
287
292
|
}
|
|
288
293
|
} else if (position === "above") {
|
|
289
294
|
top = fixed ? activatorRect.top - popoverRect.height - TOP_SPACING : activatorRect.top + window.scrollY - popoverRect.height - TOP_SPACING;
|
|
@@ -292,7 +297,7 @@ var styles = (0, _tailwindvariants.tv)({
|
|
|
292
297
|
} else if (preferredAlignment === "right") {
|
|
293
298
|
left = fixed ? activatorRect.right - popoverRect.width : activatorRect.right + window.scrollX - popoverRect.width;
|
|
294
299
|
} else if (preferredAlignment === "center") {
|
|
295
|
-
left = fixed ? activatorRect.left + activatorRect.width / 2 - popoverRect.width / 2 : activatorRect.left + window.scrollX + activatorRect.width / 2 - popoverRect.width / 2;
|
|
300
|
+
left = fixed ? activatorRect.left + activatorRect.width / 2 - popoverRect.width / 2 + horizontalOffset : activatorRect.left + window.scrollX + activatorRect.width / 2 - popoverRect.width / 2 + horizontalOffset;
|
|
296
301
|
}
|
|
297
302
|
} else if (position === "cover") {
|
|
298
303
|
top = fixed ? activatorRect.top : activatorRect.top + window.scrollY;
|
|
@@ -301,7 +306,7 @@ var styles = (0, _tailwindvariants.tv)({
|
|
|
301
306
|
} else if (preferredAlignment === "right") {
|
|
302
307
|
left = fixed ? activatorRect.right - popoverRect.width : activatorRect.right + window.scrollX - popoverRect.width;
|
|
303
308
|
} else if (preferredAlignment === "center") {
|
|
304
|
-
left = fixed ? activatorRect.left + activatorRect.width / 2 - popoverRect.width / 2 : activatorRect.left + window.scrollX + activatorRect.width / 2 - popoverRect.width / 2;
|
|
309
|
+
left = fixed ? activatorRect.left + activatorRect.width / 2 - popoverRect.width / 2 + horizontalOffset : activatorRect.left + window.scrollX + activatorRect.width / 2 - popoverRect.width / 2 + horizontalOffset;
|
|
305
310
|
}
|
|
306
311
|
}
|
|
307
312
|
// Fallback adjustments for vertical positioning (when not in left/right mode)
|
|
@@ -314,11 +319,23 @@ var styles = (0, _tailwindvariants.tv)({
|
|
|
314
319
|
}
|
|
315
320
|
}
|
|
316
321
|
// Fallback adjustments for horizontal positioning
|
|
317
|
-
if
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
+
// Only apply edge constraints if we're not using center alignment with custom offset
|
|
323
|
+
// This allows center alignment to work even near edges
|
|
324
|
+
if (preferredAlignment !== "center" || horizontalOffset === 0) {
|
|
325
|
+
if (left + popoverRect.width > windowWidth) {
|
|
326
|
+
left = windowWidth - popoverRect.width - EDGE_SPACING;
|
|
327
|
+
}
|
|
328
|
+
if (left < 0) {
|
|
329
|
+
left = EDGE_SPACING;
|
|
330
|
+
}
|
|
331
|
+
} else {
|
|
332
|
+
// For center alignment with offset, still respect edges but try to maintain centering
|
|
333
|
+
if (left + popoverRect.width > windowWidth) {
|
|
334
|
+
left = Math.max(EDGE_SPACING, windowWidth - popoverRect.width - EDGE_SPACING);
|
|
335
|
+
}
|
|
336
|
+
if (left < 0) {
|
|
337
|
+
left = EDGE_SPACING;
|
|
338
|
+
}
|
|
322
339
|
}
|
|
323
340
|
// Fallback adjustments for vertical positioning (when in left/right mode)
|
|
324
341
|
if (position === "left" || position === "right") {
|
|
@@ -28,6 +28,7 @@ var _Text = /*#__PURE__*/ _interop_require_default(require("./Text"));
|
|
|
28
28
|
var _Tooltip = /*#__PURE__*/ _interop_require_default(require("./Tooltip"));
|
|
29
29
|
var _Table = require("../styles/Table");
|
|
30
30
|
var _useIndexResourceState = require("../utilities/useIndexResourceState");
|
|
31
|
+
var _useMobile = require("../utilities/useMobile");
|
|
31
32
|
var _useMounted = require("../utilities/useMounted");
|
|
32
33
|
var _useTableScrollState = /*#__PURE__*/ _interop_require_default(require("../utilities/useTableScrollState"));
|
|
33
34
|
function _array_like_to_array(arr, len) {
|
|
@@ -502,6 +503,8 @@ var TableWrapperContext = /*#__PURE__*/ (0, _react.createContext)({});
|
|
|
502
503
|
var alignment = cellAlignment[indexAdjusted];
|
|
503
504
|
var isSortable = sortable && sortable.length > 0 && sortable[indexAdjusted];
|
|
504
505
|
var sortIndex = selectable ? indexAdjusted - 1 : indexAdjusted;
|
|
506
|
+
// Check if this cell is covered by a fixed overlay
|
|
507
|
+
var isCovered = !fixed && !reverseColumns && (fixedFirstColumns > 0 && indexAdjusted < fixedFirstColumns || fixedLastColumns > 0 && indexAdjusted >= headings.length - fixedLastColumns);
|
|
505
508
|
var sortContent = isSortable ? /*#__PURE__*/ (0, _jsxruntime.jsx)("div", {
|
|
506
509
|
className: "min-h-5 ".concat(sort.index === sortIndex ? "opacity-100" : "opacity-0 group-hover:opacity-100"),
|
|
507
510
|
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Icon.default, {
|
|
@@ -536,6 +539,7 @@ var TableWrapperContext = /*#__PURE__*/ (0, _react.createContext)({});
|
|
|
536
539
|
].includes(alignment) && sortContent
|
|
537
540
|
]
|
|
538
541
|
});
|
|
542
|
+
var hasTooltip = (heading.tooltip || heading.tooltipContent) && !isCovered;
|
|
539
543
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)(HeadingCell, {
|
|
540
544
|
className: _Table.styles.headingStyles({
|
|
541
545
|
hidden: hideCell,
|
|
@@ -553,7 +557,7 @@ var TableWrapperContext = /*#__PURE__*/ (0, _react.createContext)({});
|
|
|
553
557
|
className: _Table.styles.headingLabelContainerStyles({
|
|
554
558
|
alignment: alignment
|
|
555
559
|
}),
|
|
556
|
-
children: heading.hidden ? null :
|
|
560
|
+
children: heading.hidden ? null : hasTooltip ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_Tooltip.default, {
|
|
557
561
|
content: heading.tooltip || heading.tooltipContent,
|
|
558
562
|
preferredPosition: "above",
|
|
559
563
|
children: labelContent
|
|
@@ -669,12 +673,16 @@ var TableWrapperContext = /*#__PURE__*/ (0, _react.createContext)({});
|
|
|
669
673
|
value: {
|
|
670
674
|
columnsToRender: columnsToRender,
|
|
671
675
|
reverseColumns: reverseColumns,
|
|
672
|
-
hideCellsOnMobile: hideCellsOnMobile
|
|
676
|
+
hideCellsOnMobile: hideCellsOnMobile,
|
|
677
|
+
isFixedOverlay: fixed,
|
|
678
|
+
fixedFirstColumns: fixedFirstColumns,
|
|
679
|
+
fixedLastColumns: fixedLastColumns
|
|
673
680
|
},
|
|
674
681
|
children: /*#__PURE__*/ (0, _jsxruntime.jsxs)("table", {
|
|
675
682
|
className: _Table.styles.tableStyles(),
|
|
676
683
|
children: [
|
|
677
684
|
hasHeadings && renderHeadings({
|
|
685
|
+
fixed: fixed,
|
|
678
686
|
hidden: true,
|
|
679
687
|
columnsToRender: columnsToRender,
|
|
680
688
|
reverseColumns: reverseColumns,
|
|
@@ -807,7 +815,8 @@ var TableWrapperContext = /*#__PURE__*/ (0, _react.createContext)({});
|
|
|
807
815
|
increasedTableDensity: increasedTableDensity,
|
|
808
816
|
tableContainerRef: tableContainerRef,
|
|
809
817
|
cellAlignment: cellAlignment,
|
|
810
|
-
noBodyCellPadding: noBodyCellPadding
|
|
818
|
+
noBodyCellPadding: noBodyCellPadding,
|
|
819
|
+
columnWidths: columnWidths
|
|
811
820
|
},
|
|
812
821
|
children: /*#__PURE__*/ (0, _jsxruntime.jsxs)("div", {
|
|
813
822
|
"data-id": idRef.current,
|
|
@@ -858,8 +867,7 @@ var TableWrapperContext = /*#__PURE__*/ (0, _react.createContext)({});
|
|
|
858
867
|
children: renderTable({
|
|
859
868
|
classes: "relative overflow-hidden",
|
|
860
869
|
fixed: true,
|
|
861
|
-
columnsToRender: fixedFirstColumns
|
|
862
|
-
hideCellsOnMobile: true
|
|
870
|
+
columnsToRender: fixedFirstColumns
|
|
863
871
|
})
|
|
864
872
|
}) : /*#__PURE__*/ (0, _jsxruntime.jsx)("div", {
|
|
865
873
|
className: _Table.styles.overflowShadowStyles({
|
|
@@ -877,8 +885,7 @@ var TableWrapperContext = /*#__PURE__*/ (0, _react.createContext)({});
|
|
|
877
885
|
classes: "relative overflow-hidden",
|
|
878
886
|
fixed: true,
|
|
879
887
|
columnsToRender: fixedLastColumns,
|
|
880
|
-
reverseColumns: true
|
|
881
|
-
hideCellsOnMobile: true
|
|
888
|
+
reverseColumns: true
|
|
882
889
|
})
|
|
883
890
|
}) : /*#__PURE__*/ (0, _jsxruntime.jsx)("div", {
|
|
884
891
|
className: _Table.styles.overflowShadowStyles({
|
|
@@ -1023,8 +1030,11 @@ Table.Row.displayName = "Table.Row";
|
|
|
1023
1030
|
*/ function Cell(param) {
|
|
1024
1031
|
var tmp = param.alignment, _alignment = tmp === void 0 ? "start" : tmp, children = param.children, _param_selectionCell = param.selectionCell, selectionCell = _param_selectionCell === void 0 ? false : _param_selectionCell;
|
|
1025
1032
|
var _useContext = (0, _react.useContext)(TableContext), cellAlignment = _useContext.cellAlignment, increasedTableDensity = _useContext.increasedTableDensity, selectable = _useContext.selectable, noBodyCellPadding = _useContext.noBodyCellPadding;
|
|
1026
|
-
var _useContext1 = (0, _react.useContext)(TableWrapperContext), hideCellsOnMobile = _useContext1.hideCellsOnMobile, reverseColumns = _useContext1.reverseColumns, columnsToRender = _useContext1.columnsToRender;
|
|
1033
|
+
var _useContext1 = (0, _react.useContext)(TableWrapperContext), hideCellsOnMobile = _useContext1.hideCellsOnMobile, reverseColumns = _useContext1.reverseColumns, columnsToRender = _useContext1.columnsToRender, isFixedOverlay = _useContext1.isFixedOverlay, fixedFirstColumns = _useContext1.fixedFirstColumns, fixedLastColumns = _useContext1.fixedLastColumns;
|
|
1034
|
+
var isMobile = (0, _useMobile.useMobile)();
|
|
1027
1035
|
var columnCount = (cellAlignment === null || cellAlignment === void 0 ? void 0 : cellAlignment.length) || 0;
|
|
1036
|
+
// Use state instead of ref so changes trigger re-render
|
|
1037
|
+
var _useState = _sliced_to_array((0, _react.useState)(-1), 2), cellIndex = _useState[0], setCellIndex = _useState[1];
|
|
1028
1038
|
var cellIndexRef = (0, _react.useRef)(null);
|
|
1029
1039
|
var setCellRef = (0, _react.useCallback)(function(node) {
|
|
1030
1040
|
if (!node || cellIndexRef.current !== null) return;
|
|
@@ -1032,16 +1042,21 @@ Table.Row.displayName = "Table.Row";
|
|
|
1032
1042
|
if ((parentRow === null || parentRow === void 0 ? void 0 : parentRow.tagName) === "TR") {
|
|
1033
1043
|
var totalCells = parentRow.children.length;
|
|
1034
1044
|
var index = node.cellIndex;
|
|
1035
|
-
|
|
1045
|
+
var calculatedIndex = reverseColumns ? totalCells - columnsToRender + index - (totalCells - columnCount) : index;
|
|
1046
|
+
cellIndexRef.current = calculatedIndex;
|
|
1047
|
+
setCellIndex(calculatedIndex);
|
|
1036
1048
|
}
|
|
1037
1049
|
}, [
|
|
1038
1050
|
reverseColumns,
|
|
1039
1051
|
columnsToRender,
|
|
1040
1052
|
columnCount
|
|
1041
1053
|
]);
|
|
1042
|
-
var _cellIndexRef_current;
|
|
1043
|
-
var cellIndex = (_cellIndexRef_current = cellIndexRef.current) !== null && _cellIndexRef_current !== void 0 ? _cellIndexRef_current : -1;
|
|
1044
1054
|
var alignment = (cellAlignment === null || cellAlignment === void 0 ? void 0 : cellAlignment[cellIndex]) || _alignment;
|
|
1055
|
+
// Check if this cell is covered by a fixed overlay
|
|
1056
|
+
// When cellIndex is unknown (-1), conservatively assume the cell might be covered
|
|
1057
|
+
// if there are any fixed columns. This prevents duplicate popovers during the
|
|
1058
|
+
// brief window between initial render and when cellIndex is calculated.
|
|
1059
|
+
var isCoveredByFixedOverlay = !isFixedOverlay && !reverseColumns && (cellIndex === -1 ? fixedFirstColumns > 0 || fixedLastColumns > 0 : fixedFirstColumns > 0 && cellIndex < fixedFirstColumns || fixedLastColumns > 0 && cellIndex >= columnCount - fixedLastColumns);
|
|
1045
1060
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)("td", {
|
|
1046
1061
|
ref: setCellRef,
|
|
1047
1062
|
className: _Table.styles.cellStyles({
|
|
@@ -1052,6 +1067,7 @@ Table.Row.displayName = "Table.Row";
|
|
|
1052
1067
|
tableIsSelectable: selectable,
|
|
1053
1068
|
noBodyCellPadding: noBodyCellPadding
|
|
1054
1069
|
}),
|
|
1070
|
+
inert: !isMobile && isCoveredByFixedOverlay || undefined,
|
|
1055
1071
|
children: /*#__PURE__*/ (0, _jsxruntime.jsx)("div", {
|
|
1056
1072
|
className: _Table.styles.cellContentStyles({
|
|
1057
1073
|
alignment: alignment
|