@qoretechnologies/reqore 0.69.4 → 0.70.0
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/.claude/CLAUDE.md +20 -0
- package/.claude/skills/audit/SKILL.md +332 -0
- package/.tasks/EDITABLE_DATAVIEW.md +171 -0
- package/dist/components/Button/index.d.ts +14 -0
- package/dist/components/Button/index.d.ts.map +1 -1
- package/dist/components/Button/index.js +20 -3
- package/dist/components/Button/index.js.map +1 -1
- package/dist/components/DataView/helpers.d.ts +41 -0
- package/dist/components/DataView/helpers.d.ts.map +1 -1
- package/dist/components/DataView/helpers.js +189 -1
- package/dist/components/DataView/helpers.js.map +1 -1
- package/dist/components/DataView/index.d.ts +49 -2
- package/dist/components/DataView/index.d.ts.map +1 -1
- package/dist/components/DataView/index.js +485 -25
- package/dist/components/DataView/index.js.map +1 -1
- package/dist/components/Input/index.d.ts +6 -0
- package/dist/components/Input/index.d.ts.map +1 -1
- package/dist/components/Input/index.js +25 -10
- package/dist/components/Input/index.js.map +1 -1
- package/dist/components/KeyboardShortcut/index.d.ts +33 -0
- package/dist/components/KeyboardShortcut/index.d.ts.map +1 -0
- package/dist/components/KeyboardShortcut/index.js +69 -0
- package/dist/components/KeyboardShortcut/index.js.map +1 -0
- package/dist/components/StackedBar/index.d.ts +80 -0
- package/dist/components/StackedBar/index.d.ts.map +1 -0
- package/dist/components/StackedBar/index.js +209 -0
- package/dist/components/StackedBar/index.js.map +1 -0
- package/dist/components/Textarea/index.d.ts +5 -0
- package/dist/components/Textarea/index.d.ts.map +1 -1
- package/dist/components/Textarea/index.js +12 -3
- package/dist/components/Textarea/index.js.map +1 -1
- package/dist/containers/ReqoreProvider.d.ts.map +1 -1
- package/dist/containers/ReqoreProvider.js +3 -1
- package/dist/containers/ReqoreProvider.js.map +1 -1
- package/dist/containers/UIProvider.d.ts +1 -1
- package/dist/containers/UIProvider.d.ts.map +1 -1
- package/dist/containers/UIProvider.js.map +1 -1
- package/dist/context/ReqoreContext.d.ts +8 -0
- package/dist/context/ReqoreContext.d.ts.map +1 -1
- package/dist/context/ReqoreContext.js +1 -0
- package/dist/context/ReqoreContext.js.map +1 -1
- package/dist/helpers/shortcuts.d.ts +35 -0
- package/dist/helpers/shortcuts.d.ts.map +1 -0
- package/dist/helpers/shortcuts.js +152 -0
- package/dist/helpers/shortcuts.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/tests.json +1 -1
|
@@ -71,7 +71,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
71
71
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
72
72
|
};
|
|
73
73
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
74
|
-
exports.reqoreUnwrapEnvelope = exports.reqoreIsRecord = exports.reqoreIsEnvelope = exports.reqoreHasStructuredValue = exports.reqoreFormatScalar = exports.reqoreEnvelopeType = exports.reqoreDataValueKind = exports.reqoreDataValueIntent = exports.DEFAULT_ENVELOPE = exports.ReqoreDataView = void 0;
|
|
74
|
+
exports.reqoreUnwrapEnvelope = exports.reqoreSetAtPath = exports.reqoreRenameKeyAtPath = exports.reqoreIsRecord = exports.reqoreIsEnvelope = exports.reqoreHasStructuredValue = exports.reqoreFormatScalar = exports.reqoreEnvelopeType = exports.reqoreDeleteAtPath = exports.reqoreDataValueKind = exports.reqoreDataValueIntent = exports.reqoreCoerceValueToKind = exports.DEFAULT_ENVELOPE = exports.ReqoreDataView = void 0;
|
|
75
75
|
var jsx_runtime_1 = require("react/jsx-runtime");
|
|
76
76
|
/**
|
|
77
77
|
* `ReqoreDataView` — render a structured value (record / array / scalar)
|
|
@@ -110,7 +110,11 @@ var styled_components_1 = __importStar(require("styled-components"));
|
|
|
110
110
|
var sizes_1 = require("../../constants/sizes");
|
|
111
111
|
var colors_1 = require("../../helpers/colors");
|
|
112
112
|
var useTheme_1 = require("../../hooks/useTheme");
|
|
113
|
+
var Button_1 = __importDefault(require("../Button"));
|
|
114
|
+
var Checkbox_1 = __importDefault(require("../Checkbox"));
|
|
113
115
|
var ControlGroup_1 = __importDefault(require("../ControlGroup"));
|
|
116
|
+
var Dropdown_1 = __importDefault(require("../Dropdown"));
|
|
117
|
+
var Input_1 = __importDefault(require("../Input"));
|
|
114
118
|
var Paragraph_1 = require("../Paragraph");
|
|
115
119
|
var Panel_1 = require("../Panel");
|
|
116
120
|
var Tag_1 = __importDefault(require("../Tag"));
|
|
@@ -144,11 +148,26 @@ var TableShell = styled_components_1.default.div(templateObject_2 || (templateOb
|
|
|
144
148
|
var $nested = _a.$nested;
|
|
145
149
|
return $nested ? 'rgba(0, 0, 0, 0.45)' : 'rgba(0, 0, 0, 0.15)';
|
|
146
150
|
});
|
|
147
|
-
var Row = styled_components_1.default.div(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n display: grid;\n grid-template-columns: ", ";\n gap: ", "px;\n align-items: start;\n min-width: 0;\n padding: ", "px ", "px;\n /* Zebra striping. The stripe tint is derived from the *text* colour\n (the high-contrast colour relative to the panel surface) \u2014 that\n way an alpha lift produces a visible stripe regardless of whether\n the theme is light, dark, or custom. Painting against theme.main\n directly is invisible on a panel whose background is also\n theme.main. */\n background: ", ";\n border-bottom: 1px solid\n ", ";\n\n &:last-child {\n border-bottom: 0;\n }\n\n ", "\n\n /* The key chip's grid behaviour, applied universally \u2014 covers\n two-column rows, complex-value rows AND stacked (narrow\n container) rows in one set of rules:\n - `justify-self: start` stops the grid's default\n `justify-items: stretch` from expanding the chip to fill the\n full grid cell. The chip sizes to its content instead, only\n hitting the column cap when content actually needs it.\n - `min-width: 0` releases ReqoreTag's intrinsic min-content size\n (its longest unbreakable run) so the grid track can honour\n its `minmax(..., 220px)` cap. Without this, snake_case keys\n or UUIDs feed back into the track sizing and expand the\n column past 220px. */\n & > .reqore-data-view-key {\n justify-self: start;\n min-width: 0;\n max-width: 100%;\n }\n"], ["\n display: grid;\n grid-template-columns: ", ";\n gap: ", "px;\n align-items: start;\n min-width: 0;\n padding: ", "px ", "px;\n /* Zebra striping. The stripe tint is derived from the *text* colour\n (the high-contrast colour relative to the panel surface) \u2014 that\n way an alpha lift produces a visible stripe regardless of whether\n the theme is light, dark, or custom. Painting against theme.main\n directly is invisible on a panel whose background is also\n theme.main. */\n background: ", ";\n border-bottom: 1px solid\n ", ";\n\n &:last-child {\n border-bottom: 0;\n }\n\n ", "\n\n /* The key chip's grid behaviour, applied universally \u2014 covers\n two-column rows, complex-value rows AND stacked (narrow\n container) rows in one set of rules:\n - \\`justify-self: start\\` stops the grid's default\n \\`justify-items: stretch\\` from expanding the chip to fill the\n full grid cell. The chip sizes to its content instead, only\n hitting the column cap when content actually needs it.\n - \\`min-width: 0\\` releases ReqoreTag's intrinsic min-content size\n (its longest unbreakable run) so the grid track can honour\n its \\`minmax(..., 220px)\\` cap. Without this, snake_case keys\n or UUIDs feed back into the track sizing and expand the\n column past 220px. */\n & > .reqore-data-view-key {\n justify-self: start;\n min-width: 0;\n max-width: 100%;\n }\n"])), function (_a) {
|
|
148
|
-
var $complex = _a.$complex, $stacked = _a.$stacked;
|
|
149
|
-
|
|
151
|
+
var Row = styled_components_1.default.div(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n display: grid;\n /* Grid columns + named areas together so children land in fixed\n cells regardless of how many children render. Without\n grid-template-areas, a 3-child row (key + value + actions) in a\n 2-column grid would auto-place the value into the actions\n column. */\n grid-template-columns: ", ";\n grid-template-areas: ", ";\n\n & > .reqore-data-view-key,\n & > .reqore-data-view-key-edit-group {\n grid-area: key;\n }\n & > .reqore-data-view-value-cell {\n grid-area: value;\n }\n & > .reqore-data-view-row-actions {\n grid-area: actions;\n }\n gap: ", "px;\n align-items: start;\n min-width: 0;\n padding: ", "px ", "px;\n /* Zebra striping. The stripe tint is derived from the *text* colour\n (the high-contrast colour relative to the panel surface) \u2014 that\n way an alpha lift produces a visible stripe regardless of whether\n the theme is light, dark, or custom. Painting against theme.main\n directly is invisible on a panel whose background is also\n theme.main. */\n background: ", ";\n border-bottom: 1px solid\n ", ";\n\n &:last-child {\n border-bottom: 0;\n }\n\n ", "\n\n /* The key chip's grid behaviour, applied universally \u2014 covers\n two-column rows, complex-value rows AND stacked (narrow\n container) rows in one set of rules:\n - `justify-self: start` stops the grid's default\n `justify-items: stretch` from expanding the chip to fill the\n full grid cell. The chip sizes to its content instead, only\n hitting the column cap when content actually needs it.\n - `min-width: 0` releases ReqoreTag's intrinsic min-content size\n (its longest unbreakable run) so the grid track can honour\n its `minmax(..., 220px)` cap. Without this, snake_case keys\n or UUIDs feed back into the track sizing and expand the\n column past 220px. */\n & > .reqore-data-view-key {\n justify-self: start;\n min-width: 0;\n max-width: 100%;\n }\n"], ["\n display: grid;\n /* Grid columns + named areas together so children land in fixed\n cells regardless of how many children render. Without\n grid-template-areas, a 3-child row (key + value + actions) in a\n 2-column grid would auto-place the value into the actions\n column. */\n grid-template-columns: ", ";\n grid-template-areas: ", ";\n\n & > .reqore-data-view-key,\n & > .reqore-data-view-key-edit-group {\n grid-area: key;\n }\n & > .reqore-data-view-value-cell {\n grid-area: value;\n }\n & > .reqore-data-view-row-actions {\n grid-area: actions;\n }\n gap: ", "px;\n align-items: start;\n min-width: 0;\n padding: ", "px ", "px;\n /* Zebra striping. The stripe tint is derived from the *text* colour\n (the high-contrast colour relative to the panel surface) \u2014 that\n way an alpha lift produces a visible stripe regardless of whether\n the theme is light, dark, or custom. Painting against theme.main\n directly is invisible on a panel whose background is also\n theme.main. */\n background: ", ";\n border-bottom: 1px solid\n ", ";\n\n &:last-child {\n border-bottom: 0;\n }\n\n ", "\n\n /* The key chip's grid behaviour, applied universally \u2014 covers\n two-column rows, complex-value rows AND stacked (narrow\n container) rows in one set of rules:\n - \\`justify-self: start\\` stops the grid's default\n \\`justify-items: stretch\\` from expanding the chip to fill the\n full grid cell. The chip sizes to its content instead, only\n hitting the column cap when content actually needs it.\n - \\`min-width: 0\\` releases ReqoreTag's intrinsic min-content size\n (its longest unbreakable run) so the grid track can honour\n its \\`minmax(..., 220px)\\` cap. Without this, snake_case keys\n or UUIDs feed back into the track sizing and expand the\n column past 220px. */\n & > .reqore-data-view-key {\n justify-self: start;\n min-width: 0;\n max-width: 100%;\n }\n"])), function (_a) {
|
|
152
|
+
var $complex = _a.$complex, $stacked = _a.$stacked, $editable = _a.$editable;
|
|
153
|
+
var stacked = $complex || $stacked;
|
|
154
|
+
if ($editable) {
|
|
155
|
+
return stacked
|
|
156
|
+
? 'minmax(0, 1fr) auto'
|
|
157
|
+
: 'minmax(120px, min(34%, 220px)) minmax(0, 1fr) auto';
|
|
158
|
+
}
|
|
159
|
+
return stacked
|
|
150
160
|
? 'minmax(0, 1fr)'
|
|
151
161
|
: 'minmax(120px, min(34%, 220px)) minmax(0, 1fr)';
|
|
162
|
+
}, function (_a) {
|
|
163
|
+
var $complex = _a.$complex, $stacked = _a.$stacked, $editable = _a.$editable;
|
|
164
|
+
var stacked = $complex || $stacked;
|
|
165
|
+
if ($editable) {
|
|
166
|
+
return stacked
|
|
167
|
+
? "'key actions' 'value value'"
|
|
168
|
+
: "'key value actions'";
|
|
169
|
+
}
|
|
170
|
+
return stacked ? "'key' 'value'" : "'key value'";
|
|
152
171
|
}, function (_a) {
|
|
153
172
|
var $size = _a.$size, $complex = _a.$complex, $stacked = _a.$stacked;
|
|
154
173
|
return $complex || $stacked ? sizes_1.GAP_FROM_SIZE[$size] : 8;
|
|
@@ -179,7 +198,7 @@ var ArrayStack = styled_components_1.default.div(templateObject_7 || (templateOb
|
|
|
179
198
|
var $size = _a.$size;
|
|
180
199
|
return sizes_1.GAP_FROM_SIZE[$size];
|
|
181
200
|
});
|
|
182
|
-
var ArrayItem = styled_components_1.default.div(templateObject_8 || (templateObject_8 = __makeTemplateObject(["\n min-width: 0;\n max-width: 100%;\n /* More left padding than the other three sides so the item index\n and contents read as visually inset under the parent \u2014 mirrors\n the IDE pattern of \"nested = inset\". */\n padding: ", "px\n ", "px\n ", "px\n ", "px;\n
|
|
201
|
+
var ArrayItem = styled_components_1.default.div(templateObject_8 || (templateObject_8 = __makeTemplateObject(["\n min-width: 0;\n max-width: 100%;\n /* Two-column flex layout: content (index + value) on the left,\n hover-revealed action cell on the right. Keeps the actions\n properly inside the item's bounds instead of leaning on absolute\n positioning. */\n display: flex;\n flex-flow: row;\n align-items: start;\n gap: 8px;\n /* More left padding than the other three sides so the item index\n and contents read as visually inset under the parent \u2014 mirrors\n the IDE pattern of \"nested = inset\". */\n padding: ", "px\n ", "px\n ", "px\n ", "px;\n border: 1px solid ", ";\n border-left: 2px solid ", ";\n border-radius: ", "px;\n background: rgba(0, 0, 0, 0.45);\n"], ["\n min-width: 0;\n max-width: 100%;\n /* Two-column flex layout: content (index + value) on the left,\n hover-revealed action cell on the right. Keeps the actions\n properly inside the item's bounds instead of leaning on absolute\n positioning. */\n display: flex;\n flex-flow: row;\n align-items: start;\n gap: 8px;\n /* More left padding than the other three sides so the item index\n and contents read as visually inset under the parent \u2014 mirrors\n the IDE pattern of \"nested = inset\". */\n padding: ", "px\n ", "px\n ", "px\n ", "px;\n border: 1px solid ", ";\n border-left: 2px solid ", ";\n border-radius: ", "px;\n background: rgba(0, 0, 0, 0.45);\n"])), function (_a) {
|
|
183
202
|
var $size = _a.$size;
|
|
184
203
|
return sizes_1.PADDING_FROM_SIZE[$size];
|
|
185
204
|
}, function (_a) {
|
|
@@ -201,7 +220,11 @@ var ArrayItem = styled_components_1.default.div(templateObject_8 || (templateObj
|
|
|
201
220
|
var $size = _a.$size;
|
|
202
221
|
return sizes_1.RADIUS_FROM_SIZE[$size];
|
|
203
222
|
});
|
|
204
|
-
|
|
223
|
+
/** Content column for an array item — wraps the item's index +
|
|
224
|
+
* rendered value so the flex row's other cell (the action group)
|
|
225
|
+
* sits to the right without competing for width. */
|
|
226
|
+
var ArrayItemContent = styled_components_1.default.div(templateObject_9 || (templateObject_9 = __makeTemplateObject(["\n flex: 1 1 auto;\n min-width: 0;\n"], ["\n flex: 1 1 auto;\n min-width: 0;\n"])));
|
|
227
|
+
var ArrayItemIndex = styled_components_1.default.span(templateObject_10 || (templateObject_10 = __makeTemplateObject(["\n display: inline-block;\n margin-bottom: ", "px;\n padding: 1px 6px;\n border-radius: 4px;\n background: ", ";\n color: ", ";\n font-family: ", ";\n font-size: 11px;\n opacity: 0.78;\n"], ["\n display: inline-block;\n margin-bottom: ", "px;\n padding: 1px 6px;\n border-radius: 4px;\n background: ", ";\n color: ", ";\n font-family: ", ";\n font-size: 11px;\n opacity: 0.78;\n"])), function (_a) {
|
|
205
228
|
var $size = _a.$size;
|
|
206
229
|
return sizes_1.GAP_FROM_SIZE[$size];
|
|
207
230
|
}, function (_a) {
|
|
@@ -211,12 +234,12 @@ var ArrayItemIndex = styled_components_1.default.span(templateObject_9 || (templ
|
|
|
211
234
|
var $theme = _a.$theme;
|
|
212
235
|
return (0, colors_1.getReadableColor)($theme);
|
|
213
236
|
}, MONO_FONT);
|
|
214
|
-
var ScalarRow = (0, styled_components_1.default)(ControlGroup_1.default)(
|
|
215
|
-
var SectionDetails = styled_components_1.default.details(
|
|
237
|
+
var ScalarRow = (0, styled_components_1.default)(ControlGroup_1.default)(templateObject_11 || (templateObject_11 = __makeTemplateObject(["\n flex-wrap: wrap;\n"], ["\n flex-wrap: wrap;\n"])));
|
|
238
|
+
var SectionDetails = styled_components_1.default.details(templateObject_12 || (templateObject_12 = __makeTemplateObject(["\n min-width: 0;\n max-width: 100%;\n\n &[open] > summary {\n margin-bottom: ", "px;\n }\n"], ["\n min-width: 0;\n max-width: 100%;\n\n &[open] > summary {\n margin-bottom: ", "px;\n }\n"])), function (_a) {
|
|
216
239
|
var $size = _a.$size;
|
|
217
240
|
return sizes_1.GAP_FROM_SIZE[$size];
|
|
218
241
|
});
|
|
219
|
-
var SectionSummary = styled_components_1.default.summary(
|
|
242
|
+
var SectionSummary = styled_components_1.default.summary(templateObject_13 || (templateObject_13 = __makeTemplateObject(["\n display: inline-flex;\n align-items: center;\n gap: 6px;\n width: fit-content;\n cursor: pointer;\n user-select: none;\n font-family: ", ";\n font-size: ", "px;\n font-weight: 700;\n /* Section labels MUST stay readable \u2014 they're the only way the\n operator knows what's nested below. We derive a high-contrast\n colour from the panel's surface instead of falling back to\n theme.main, which would be the SAME colour as the panel\n background on most themes (invisible). */\n color: ", ";\n opacity: 0.85;\n transition: opacity 0.15s ease-out;\n\n &:hover {\n opacity: 1;\n }\n\n &::-webkit-details-marker {\n display: none;\n }\n\n &::before {\n content: '\u25B8';\n display: inline-block;\n transition: transform 0.15s ease-out;\n transform-origin: 50% 50%;\n }\n\n ", "[open] > &::before {\n transform: rotate(90deg);\n }\n"], ["\n display: inline-flex;\n align-items: center;\n gap: 6px;\n width: fit-content;\n cursor: pointer;\n user-select: none;\n font-family: ", ";\n font-size: ", "px;\n font-weight: 700;\n /* Section labels MUST stay readable \u2014 they're the only way the\n operator knows what's nested below. We derive a high-contrast\n colour from the panel's surface instead of falling back to\n theme.main, which would be the SAME colour as the panel\n background on most themes (invisible). */\n color: ", ";\n opacity: 0.85;\n transition: opacity 0.15s ease-out;\n\n &:hover {\n opacity: 1;\n }\n\n &::-webkit-details-marker {\n display: none;\n }\n\n &::before {\n content: '\u25B8';\n display: inline-block;\n transition: transform 0.15s ease-out;\n transform-origin: 50% 50%;\n }\n\n ", "[open] > &::before {\n transform: rotate(90deg);\n }\n"])), MONO_FONT, function (_a) {
|
|
220
243
|
var $size = _a.$size;
|
|
221
244
|
return sizes_1.TEXT_FROM_SIZE[$size] - 2;
|
|
222
245
|
}, function (_a) {
|
|
@@ -291,6 +314,347 @@ var PreservedDetails = (0, react_1.memo)(function (_a) {
|
|
|
291
314
|
return ((0, jsx_runtime_1.jsxs)(SectionDetails, { "$size": size, "$theme": theme, open: open, children: [(0, jsx_runtime_1.jsx)(SectionSummary, { ref: summaryRef, "$size": size, "$theme": theme, role: 'button', "aria-expanded": open, tabIndex: 0, onClick: onSummaryClick, onKeyDown: onSummaryKey, children: label }), children] }));
|
|
292
315
|
});
|
|
293
316
|
PreservedDetails.displayName = 'ReqoreDataView.PreservedDetails';
|
|
317
|
+
/** Render the read-only value chip for a scalar leaf. Extracted so
|
|
318
|
+
* both the read-only view and the click-to-edit cell share one
|
|
319
|
+
* rendering — keeps the "before / after" look of an edited row
|
|
320
|
+
* perfectly aligned with rows you can't edit. */
|
|
321
|
+
var renderScalarChip = function (value, type, ctx, path) {
|
|
322
|
+
var scalar = (0, helpers_1.reqoreFormatScalar)(value, type, ctx.scalarOptions);
|
|
323
|
+
var kind = type ? (0, helpers_1.reqoreDataValueKind)(value, type) : scalar.kind;
|
|
324
|
+
var intent = (0, helpers_1.reqoreDataValueIntent)(kind);
|
|
325
|
+
return ((0, jsx_runtime_1.jsx)(Tag_1.default, { size: ctx.size, flat: false, minimal: true, wrap: true, label: scalar.display, intent: intent, effect: { weight: 'bold' }, onClick: ctx.onItemClick ? function () { return ctx.onItemClick(value, path); } : undefined, className: 'reqore-data-view-value' }));
|
|
326
|
+
};
|
|
327
|
+
var EditCellShell = styled_components_1.default.span(templateObject_14 || (templateObject_14 = __makeTemplateObject(["\n display: inline-flex;\n align-items: center;\n min-width: 0;\n max-width: 100%;\n cursor: ", ";\n\n /* Subtle hover hint on the chip so operators know it's clickable \u2014\n without shouting. The chip itself doesn't gain border / shadow;\n we just lift its outline a hair. */\n &:not([data-editing='true']):hover .reqore-data-view-value {\n outline: 1px dashed\n ", ";\n outline-offset: 1px;\n }\n"], ["\n display: inline-flex;\n align-items: center;\n min-width: 0;\n max-width: 100%;\n cursor: ", ";\n\n /* Subtle hover hint on the chip so operators know it's clickable \u2014\n without shouting. The chip itself doesn't gain border / shadow;\n we just lift its outline a hair. */\n &:not([data-editing='true']):hover .reqore-data-view-value {\n outline: 1px dashed\n ", ";\n outline-offset: 1px;\n }\n"])), function (_a) {
|
|
328
|
+
var $editing = _a.$editing;
|
|
329
|
+
return ($editing ? 'text' : 'pointer');
|
|
330
|
+
}, function (_a) {
|
|
331
|
+
var theme = _a.theme;
|
|
332
|
+
return (0, polished_1.rgba)((0, colors_1.getReadableColor)(theme), 0.35);
|
|
333
|
+
});
|
|
334
|
+
var initialDraftFor = function (value, k) {
|
|
335
|
+
if (k === 'boolean')
|
|
336
|
+
return value === true;
|
|
337
|
+
return value === null || value === undefined ? '' : String(value);
|
|
338
|
+
};
|
|
339
|
+
var EditableScalarCell = (0, react_1.memo)(function (_a) {
|
|
340
|
+
var _b;
|
|
341
|
+
var value = _a.value, kind = _a.kind, type = _a.type, ctx = _a.ctx, path = _a.path;
|
|
342
|
+
var commit = ctx.commitScalar;
|
|
343
|
+
var isNumber = kind === 'number';
|
|
344
|
+
var isBoolean = kind === 'boolean';
|
|
345
|
+
var _c = (0, react_1.useState)(false), editing = _c[0], setEditing = _c[1];
|
|
346
|
+
var _d = (0, react_1.useState)(initialDraftFor(value, kind)), draft = _d[0], setDraft = _d[1];
|
|
347
|
+
var inputRef = (0, react_1.useRef)(null);
|
|
348
|
+
// Re-sync the local draft when the prop value or kind changes
|
|
349
|
+
// externally. Editing keeps its own draft until commit/cancel.
|
|
350
|
+
(0, react_1.useLayoutEffect)(function () {
|
|
351
|
+
if (editing)
|
|
352
|
+
return;
|
|
353
|
+
setDraft(initialDraftFor(value, kind));
|
|
354
|
+
}, [value, kind, editing]);
|
|
355
|
+
// Focus the input when entering edit mode (text / number cells
|
|
356
|
+
// only — boolean's checkbox is keyboard-accessible by tab).
|
|
357
|
+
(0, react_1.useLayoutEffect)(function () {
|
|
358
|
+
var _a;
|
|
359
|
+
if (!editing || isBoolean)
|
|
360
|
+
return;
|
|
361
|
+
var node = inputRef.current;
|
|
362
|
+
if (!node)
|
|
363
|
+
return;
|
|
364
|
+
node.focus();
|
|
365
|
+
(_a = node.select) === null || _a === void 0 ? void 0 : _a.call(node);
|
|
366
|
+
}, [editing, isBoolean]);
|
|
367
|
+
var startEditing = (0, react_1.useCallback)(function () {
|
|
368
|
+
if (!commit)
|
|
369
|
+
return;
|
|
370
|
+
setDraft(initialDraftFor(value, kind));
|
|
371
|
+
setEditing(true);
|
|
372
|
+
}, [commit, kind, value]);
|
|
373
|
+
var cancelEditing = (0, react_1.useCallback)(function () {
|
|
374
|
+
setDraft(initialDraftFor(value, kind));
|
|
375
|
+
setEditing(false);
|
|
376
|
+
}, [kind, value]);
|
|
377
|
+
var commitDraft = (0, react_1.useCallback)(function () {
|
|
378
|
+
if (!commit) {
|
|
379
|
+
setEditing(false);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (isBoolean) {
|
|
383
|
+
commit(path, draft === true);
|
|
384
|
+
setEditing(false);
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
var text = typeof draft === 'string' ? draft : '';
|
|
388
|
+
if (isNumber) {
|
|
389
|
+
if (text.trim() === '') {
|
|
390
|
+
commit(path, null);
|
|
391
|
+
setEditing(false);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
var parsed = Number(text);
|
|
395
|
+
if (Number.isNaN(parsed)) {
|
|
396
|
+
cancelEditing();
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
commit(path, parsed);
|
|
400
|
+
setEditing(false);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
// String / null cells. An empty edit on a null leaf is a no-op
|
|
404
|
+
// (don't accidentally upgrade null → empty string).
|
|
405
|
+
if (text === '' && (value === null || value === undefined)) {
|
|
406
|
+
setEditing(false);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
commit(path, text);
|
|
410
|
+
setEditing(false);
|
|
411
|
+
}, [cancelEditing, commit, draft, isBoolean, isNumber, path, value]);
|
|
412
|
+
if (!editing) {
|
|
413
|
+
return ((0, jsx_runtime_1.jsx)(EditCellShell, { "data-editing": 'false', onClick: function (e) {
|
|
414
|
+
e.stopPropagation();
|
|
415
|
+
startEditing();
|
|
416
|
+
}, onKeyDown: function (e) {
|
|
417
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
418
|
+
e.preventDefault();
|
|
419
|
+
startEditing();
|
|
420
|
+
}
|
|
421
|
+
}, role: 'button', tabIndex: 0, "aria-label": 'Edit value', children: renderScalarChip(value, type, ctx, path) }));
|
|
422
|
+
}
|
|
423
|
+
// Inline type-change. Coerces the CURRENT DRAFT (in its
|
|
424
|
+
// canonical form for the current kind — string for text/numeric
|
|
425
|
+
// inputs, boolean for the checkbox) to the picked kind. A user
|
|
426
|
+
// who has typed `42` and then realises they meant Number keeps
|
|
427
|
+
// the `42` they typed; a user who has clicked the checkbox `on`
|
|
428
|
+
// and switches to String gets `"true"`.
|
|
429
|
+
//
|
|
430
|
+
// Picking `string` / `number` / `boolean` keeps the cell in edit
|
|
431
|
+
// mode and re-initialises the draft to the coerced value (so the
|
|
432
|
+
// input swap doesn't visually drop the user's intent). Picking
|
|
433
|
+
// `object` / `array` / `null` commits the coerced value and
|
|
434
|
+
// exits so the right control takes over (structural view / "—"
|
|
435
|
+
// chip).
|
|
436
|
+
var handlePickType = function (newKind) {
|
|
437
|
+
var _a;
|
|
438
|
+
if (newKind === kind)
|
|
439
|
+
return;
|
|
440
|
+
var coerced = (0, helpers_1.reqoreCoerceValueToKind)(draft, newKind);
|
|
441
|
+
(_a = ctx.commitTypeChange) === null || _a === void 0 ? void 0 : _a.call(ctx, path, newKind);
|
|
442
|
+
if (newKind === 'string' || newKind === 'number') {
|
|
443
|
+
setDraft(coerced === null || coerced === undefined ? '' : String(coerced));
|
|
444
|
+
}
|
|
445
|
+
else if (newKind === 'boolean') {
|
|
446
|
+
setDraft(coerced === true);
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
setEditing(false);
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
var currentTypeItem = TYPE_PICKER_ITEMS.find(function (entry) { return entry.kind === kind; });
|
|
453
|
+
return ((0, jsx_runtime_1.jsxs)(ControlGroup_1.default, { gapSize: 'tiny', verticalAlign: 'center', size: ctx.size, className: 'reqore-data-view-edit-group', children: [isBoolean ? ((0, jsx_runtime_1.jsx)(Checkbox_1.default, { checked: draft === true, size: ctx.size,
|
|
454
|
+
// Toggle the LOCAL draft only — Save commits, Cancel
|
|
455
|
+
// discards. Keeps the edit semantics identical to
|
|
456
|
+
// text/number cells.
|
|
457
|
+
onClick: function () { return setDraft(!(draft === true)); }, className: 'reqore-data-view-edit-bool' })) : ((0, jsx_runtime_1.jsx)(Input_1.default, { size: ctx.size, type: isNumber ? 'number' : 'text', value: typeof draft === 'string' ? draft : '', ref: (function (node) {
|
|
458
|
+
if (node instanceof HTMLElement) {
|
|
459
|
+
inputRef.current = node.querySelector('input');
|
|
460
|
+
}
|
|
461
|
+
}), onChange: function (event) {
|
|
462
|
+
return setDraft(event.target.value);
|
|
463
|
+
}, onBlur: commitDraft, onKeyDown: function (event) {
|
|
464
|
+
if (event.key === 'Enter') {
|
|
465
|
+
event.preventDefault();
|
|
466
|
+
commitDraft();
|
|
467
|
+
}
|
|
468
|
+
else if (event.key === 'Escape') {
|
|
469
|
+
event.preventDefault();
|
|
470
|
+
cancelEditing();
|
|
471
|
+
}
|
|
472
|
+
}, className: 'reqore-data-view-edit' })), ctx.commitTypeChange ? ((0, jsx_runtime_1.jsx)(Dropdown_1.default, { size: ctx.size, icon: (_b = currentTypeItem === null || currentTypeItem === void 0 ? void 0 : currentTypeItem.icon) !== null && _b !== void 0 ? _b : 'TextWrap', tooltip: 'Change type', className: 'reqore-data-view-edit-type', items: TYPE_PICKER_ITEMS.map(function (entry) { return ({
|
|
473
|
+
label: entry.label,
|
|
474
|
+
icon: entry.icon,
|
|
475
|
+
selected: entry.kind === kind,
|
|
476
|
+
onClick: function () { return handlePickType(entry.kind); },
|
|
477
|
+
}); }) })) : null, (0, jsx_runtime_1.jsx)(Button_1.default, { size: ctx.size, icon: 'CheckLine', intent: 'success', flat: true, minimal: true, tooltip: 'Save (Enter)', onMouseDown: function (e) {
|
|
478
|
+
e.preventDefault();
|
|
479
|
+
commitDraft();
|
|
480
|
+
}, className: 'reqore-data-view-edit-commit' }), (0, jsx_runtime_1.jsx)(Button_1.default, { size: ctx.size, icon: 'CloseLine', flat: true, minimal: true, tooltip: 'Cancel (Esc)', onMouseDown: function (e) {
|
|
481
|
+
e.preventDefault();
|
|
482
|
+
cancelEditing();
|
|
483
|
+
}, className: 'reqore-data-view-edit-cancel' })] }));
|
|
484
|
+
});
|
|
485
|
+
EditableScalarCell.displayName = 'ReqoreDataView.EditableScalarCell';
|
|
486
|
+
var EditableKeyCell = (0, react_1.memo)(function (_a) {
|
|
487
|
+
var _b;
|
|
488
|
+
var keyName = _a.keyName, siblingKeys = _a.siblingKeys, parentPath = _a.parentPath, ctx = _a.ctx;
|
|
489
|
+
var commit = ctx.commitRename;
|
|
490
|
+
var _c = (0, react_1.useState)(false), editing = _c[0], setEditing = _c[1];
|
|
491
|
+
var _d = (0, react_1.useState)(keyName), draft = _d[0], setDraft = _d[1];
|
|
492
|
+
var inputRef = (0, react_1.useRef)(null);
|
|
493
|
+
(0, react_1.useLayoutEffect)(function () {
|
|
494
|
+
if (editing)
|
|
495
|
+
return;
|
|
496
|
+
setDraft(keyName);
|
|
497
|
+
}, [keyName, editing]);
|
|
498
|
+
(0, react_1.useLayoutEffect)(function () {
|
|
499
|
+
var _a;
|
|
500
|
+
if (!editing)
|
|
501
|
+
return;
|
|
502
|
+
var node = inputRef.current;
|
|
503
|
+
if (!node)
|
|
504
|
+
return;
|
|
505
|
+
node.focus();
|
|
506
|
+
(_a = node.select) === null || _a === void 0 ? void 0 : _a.call(node);
|
|
507
|
+
}, [editing]);
|
|
508
|
+
var start = (0, react_1.useCallback)(function () {
|
|
509
|
+
if (!commit)
|
|
510
|
+
return;
|
|
511
|
+
setDraft(keyName);
|
|
512
|
+
setEditing(true);
|
|
513
|
+
}, [commit, keyName]);
|
|
514
|
+
var cancel = (0, react_1.useCallback)(function () {
|
|
515
|
+
setDraft(keyName);
|
|
516
|
+
setEditing(false);
|
|
517
|
+
}, [keyName]);
|
|
518
|
+
var submit = (0, react_1.useCallback)(function () {
|
|
519
|
+
var trimmed = draft.trim();
|
|
520
|
+
if (!commit || !trimmed || trimmed === keyName) {
|
|
521
|
+
cancel();
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
if (siblingKeys.includes(trimmed)) {
|
|
525
|
+
cancel();
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
commit(parentPath, keyName, trimmed);
|
|
529
|
+
setEditing(false);
|
|
530
|
+
}, [cancel, commit, draft, keyName, parentPath, siblingKeys]);
|
|
531
|
+
if (!editing) {
|
|
532
|
+
return ((0, jsx_runtime_1.jsx)(EditCellShell, { "data-editing": 'false', onClick: function (e) {
|
|
533
|
+
e.stopPropagation();
|
|
534
|
+
start();
|
|
535
|
+
}, role: 'button', tabIndex: 0, "aria-label": 'Rename key', children: (0, jsx_runtime_1.jsx)(Tag_1.default, { size: ctx.size, flat: false, minimal: true, wrap: true, intent: ctx.keyIntent === null ? undefined : (_b = ctx.keyIntent) !== null && _b !== void 0 ? _b : 'info', color: ctx.keyColor, label: keyName, effect: { weight: 'bold' }, className: 'reqore-data-view-key' }) }));
|
|
536
|
+
}
|
|
537
|
+
return ((0, jsx_runtime_1.jsxs)(ControlGroup_1.default, { gapSize: 'tiny', verticalAlign: 'center', size: ctx.size, className: 'reqore-data-view-key-edit-group', children: [(0, jsx_runtime_1.jsx)(Input_1.default, { size: ctx.size, value: draft, ref: (function (node) {
|
|
538
|
+
if (node instanceof HTMLElement) {
|
|
539
|
+
inputRef.current = node.querySelector('input');
|
|
540
|
+
}
|
|
541
|
+
}), onChange: function (e) {
|
|
542
|
+
return setDraft(e.target.value);
|
|
543
|
+
}, onBlur: submit, onKeyDown: function (e) {
|
|
544
|
+
if (e.key === 'Enter') {
|
|
545
|
+
e.preventDefault();
|
|
546
|
+
submit();
|
|
547
|
+
}
|
|
548
|
+
else if (e.key === 'Escape') {
|
|
549
|
+
e.preventDefault();
|
|
550
|
+
cancel();
|
|
551
|
+
}
|
|
552
|
+
}, className: 'reqore-data-view-key-edit' }), (0, jsx_runtime_1.jsx)(Button_1.default, { size: ctx.size, icon: 'CheckLine', intent: 'success', flat: true, minimal: true, tooltip: 'Rename (Enter)', onMouseDown: function (e) {
|
|
553
|
+
e.preventDefault();
|
|
554
|
+
submit();
|
|
555
|
+
}, className: 'reqore-data-view-key-edit-commit' }), (0, jsx_runtime_1.jsx)(Button_1.default, { size: ctx.size, icon: 'CloseLine', flat: true, minimal: true, tooltip: 'Cancel (Esc)', onMouseDown: function (e) {
|
|
556
|
+
e.preventDefault();
|
|
557
|
+
cancel();
|
|
558
|
+
}, className: 'reqore-data-view-key-edit-cancel' })] }));
|
|
559
|
+
});
|
|
560
|
+
EditableKeyCell.displayName = 'ReqoreDataView.EditableKeyCell';
|
|
561
|
+
/** Hover-revealed row action group — currently the delete button.
|
|
562
|
+
* Renders as a normal grid cell at the trailing edge of each row so
|
|
563
|
+
* it always sits cleanly inside the row's bounds (no absolute
|
|
564
|
+
* positioning, no overflow past the panel's rounded corner). The
|
|
565
|
+
* group's `opacity` is `0` by default and promoted to `1` on row
|
|
566
|
+
* hover via the parent `Row`'s `:hover` rule. The cell itself stays
|
|
567
|
+
* in the layout so the row width doesn't jump as the user hovers. */
|
|
568
|
+
var RowActionsContainer = styled_components_1.default.div(templateObject_15 || (templateObject_15 = __makeTemplateObject(["\n display: inline-flex;\n align-items: center;\n gap: 4px;\n /* Pad the action cell off the row's right edge a touch so the button\n doesn't kiss the panel's rounded corner. */\n padding-right: 2px;\n opacity: 0;\n transition: opacity 0.12s ease-out;\n pointer-events: none;\n\n .reqore-data-view-row:hover & {\n opacity: 1;\n pointer-events: auto;\n }\n\n /* Keep the actions visible when any child is focused (keyboard\n navigation must reveal them too). */\n &:focus-within {\n opacity: 1;\n pointer-events: auto;\n }\n"], ["\n display: inline-flex;\n align-items: center;\n gap: 4px;\n /* Pad the action cell off the row's right edge a touch so the button\n doesn't kiss the panel's rounded corner. */\n padding-right: 2px;\n opacity: 0;\n transition: opacity 0.12s ease-out;\n pointer-events: none;\n\n .reqore-data-view-row:hover & {\n opacity: 1;\n pointer-events: auto;\n }\n\n /* Keep the actions visible when any child is focused (keyboard\n navigation must reveal them too). */\n &:focus-within {\n opacity: 1;\n pointer-events: auto;\n }\n"])));
|
|
569
|
+
var RowActions = (0, react_1.memo)(function (_a) {
|
|
570
|
+
var ctx = _a.ctx, path = _a.path, ariaLabel = _a.ariaLabel;
|
|
571
|
+
if (!ctx.commitDelete)
|
|
572
|
+
return null;
|
|
573
|
+
return ((0, jsx_runtime_1.jsx)(RowActionsContainer, { className: 'reqore-data-view-row-actions', onClick: function (e) { return e.stopPropagation(); }, children: (0, jsx_runtime_1.jsx)(Button_1.default, { size: ctx.size, icon: 'DeleteBin6Line', flat: true, minimal: true, tooltip: ariaLabel, intent: 'danger', onClick: function () { return ctx.commitDelete(path); }, className: 'reqore-data-view-row-delete' }) }));
|
|
574
|
+
});
|
|
575
|
+
RowActions.displayName = 'ReqoreDataView.RowActions';
|
|
576
|
+
/** Default value for a new entry of the picked type. */
|
|
577
|
+
var defaultForKind = function (kind) {
|
|
578
|
+
switch (kind) {
|
|
579
|
+
case 'string':
|
|
580
|
+
return '';
|
|
581
|
+
case 'number':
|
|
582
|
+
return 0;
|
|
583
|
+
case 'boolean':
|
|
584
|
+
return false;
|
|
585
|
+
case 'object':
|
|
586
|
+
return {};
|
|
587
|
+
case 'array':
|
|
588
|
+
return [];
|
|
589
|
+
case 'null':
|
|
590
|
+
default:
|
|
591
|
+
return null;
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
var TYPE_PICKER_ITEMS = [
|
|
595
|
+
{ kind: 'string', label: 'String', icon: 'TextWrap' },
|
|
596
|
+
{ kind: 'number', label: 'Number', icon: 'Hashtag' },
|
|
597
|
+
{ kind: 'boolean', label: 'Boolean', icon: 'CheckboxLine' },
|
|
598
|
+
{ kind: 'object', label: 'Object (hash)', icon: 'BracesLine' },
|
|
599
|
+
{ kind: 'array', label: 'Array (list)', icon: 'BracketsLine' },
|
|
600
|
+
{ kind: 'null', label: 'Null', icon: 'CircleLine' },
|
|
601
|
+
];
|
|
602
|
+
var AddRowShell = styled_components_1.default.div(templateObject_16 || (templateObject_16 = __makeTemplateObject(["\n display: flex;\n flex-flow: row wrap;\n gap: 6px;\n align-items: center;\n padding: 8px;\n border-top: 1px dashed\n ", ";\n background: rgba(0, 0, 0, 0.12);\n"], ["\n display: flex;\n flex-flow: row wrap;\n gap: 6px;\n align-items: center;\n padding: 8px;\n border-top: 1px dashed\n ", ";\n background: rgba(0, 0, 0, 0.12);\n"])), function (_a) {
|
|
603
|
+
var theme = _a.theme;
|
|
604
|
+
return (0, polished_1.rgba)((0, colors_1.getReadableColor)(theme), 0.2);
|
|
605
|
+
});
|
|
606
|
+
var AddEntryAffordance = (0, react_1.memo)(function (_a) {
|
|
607
|
+
var _b;
|
|
608
|
+
var ctx = _a.ctx, parentPath = _a.parentPath, context = _a.context;
|
|
609
|
+
var _c = (0, react_1.useState)(false), open = _c[0], setOpen = _c[1];
|
|
610
|
+
var _d = (0, react_1.useState)(''), key = _d[0], setKey = _d[1];
|
|
611
|
+
var _e = (0, react_1.useState)('string'), valueKind = _e[0], setValueKind = _e[1];
|
|
612
|
+
if (!ctx.commitAdd)
|
|
613
|
+
return null;
|
|
614
|
+
var reset = function () {
|
|
615
|
+
setOpen(false);
|
|
616
|
+
setKey('');
|
|
617
|
+
setValueKind('string');
|
|
618
|
+
};
|
|
619
|
+
var submit = function () {
|
|
620
|
+
var initial = defaultForKind(valueKind);
|
|
621
|
+
if (context.kind === 'record') {
|
|
622
|
+
var trimmed = key.trim();
|
|
623
|
+
if (!trimmed)
|
|
624
|
+
return;
|
|
625
|
+
if (context.existingKeys.includes(trimmed))
|
|
626
|
+
return;
|
|
627
|
+
ctx.commitAdd(parentPath, trimmed, initial);
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
ctx.commitAdd(parentPath, context.length, initial);
|
|
631
|
+
}
|
|
632
|
+
reset();
|
|
633
|
+
};
|
|
634
|
+
if (!open) {
|
|
635
|
+
return ((0, jsx_runtime_1.jsx)(AddRowShell, { className: 'reqore-data-view-add-row', "data-state": 'collapsed', children: (0, jsx_runtime_1.jsx)(Button_1.default, { size: ctx.size, icon: 'AddLine', flat: true, minimal: true, onClick: function () { return setOpen(true); }, label: context.kind === 'record' ? 'Add property' : 'Add item' }) }));
|
|
636
|
+
}
|
|
637
|
+
var typeItem = TYPE_PICKER_ITEMS.find(function (entry) { return entry.kind === valueKind; });
|
|
638
|
+
return ((0, jsx_runtime_1.jsxs)(AddRowShell, { className: 'reqore-data-view-add-row', "data-state": 'expanded', onKeyDown: function (e) {
|
|
639
|
+
if (e.key === 'Escape') {
|
|
640
|
+
e.preventDefault();
|
|
641
|
+
reset();
|
|
642
|
+
}
|
|
643
|
+
}, children: [context.kind === 'record' ? ((0, jsx_runtime_1.jsx)(Input_1.default, { size: ctx.size, placeholder: 'property name', value: key, onChange: function (e) {
|
|
644
|
+
return setKey(e.target.value);
|
|
645
|
+
}, onKeyDown: function (e) {
|
|
646
|
+
if (e.key === 'Enter') {
|
|
647
|
+
e.preventDefault();
|
|
648
|
+
submit();
|
|
649
|
+
}
|
|
650
|
+
}, className: 'reqore-data-view-add-key' })) : null, (0, jsx_runtime_1.jsx)(Dropdown_1.default, { size: ctx.size, icon: typeItem === null || typeItem === void 0 ? void 0 : typeItem.icon, label: (_b = typeItem === null || typeItem === void 0 ? void 0 : typeItem.label) !== null && _b !== void 0 ? _b : 'String', className: 'reqore-data-view-add-type', items: TYPE_PICKER_ITEMS.map(function (entry) { return ({
|
|
651
|
+
label: entry.label,
|
|
652
|
+
icon: entry.icon,
|
|
653
|
+
selected: entry.kind === valueKind,
|
|
654
|
+
onClick: function () { return setValueKind(entry.kind); },
|
|
655
|
+
}); }) }), (0, jsx_runtime_1.jsx)(Button_1.default, { size: ctx.size, icon: 'CheckLine', intent: 'success', flat: true, minimal: true, onClick: submit, label: 'Add', className: 'reqore-data-view-add-commit' }), (0, jsx_runtime_1.jsx)(Button_1.default, { size: ctx.size, icon: 'CloseLine', flat: true, minimal: true, onClick: reset, tooltip: 'Cancel', className: 'reqore-data-view-add-cancel' })] }));
|
|
656
|
+
});
|
|
657
|
+
AddEntryAffordance.displayName = 'ReqoreDataView.AddEntryAffordance';
|
|
294
658
|
var isInlineableScalarValue = function (value, ctx) {
|
|
295
659
|
var unwrapped = ctx.envelope === false ? value : (0, helpers_1.reqoreUnwrapEnvelope)(value, ctx.envelope);
|
|
296
660
|
if (typeof unwrapped === 'string' && ctx.parseEmbedded && ctx.parseEmbedded(unwrapped)) {
|
|
@@ -303,6 +667,15 @@ var renderScalar = function (value, type, ctx, path) {
|
|
|
303
667
|
var kind = type ? (0, helpers_1.reqoreDataValueKind)(value, type) : scalar.kind;
|
|
304
668
|
var intent = (0, helpers_1.reqoreDataValueIntent)(kind);
|
|
305
669
|
var displayType = type !== null && type !== void 0 ? type : kind;
|
|
670
|
+
// Editable mode: render the click-to-edit cell instead of the
|
|
671
|
+
// static chip. Date-typed scalars stay read-only until the date
|
|
672
|
+
// picker lands.
|
|
673
|
+
if (ctx.editable && kind !== 'date' && kind !== 'object' && kind !== 'array') {
|
|
674
|
+
var cell = ((0, jsx_runtime_1.jsx)(EditableScalarCell, { value: value, kind: kind, type: type, ctx: ctx, path: path }));
|
|
675
|
+
if (!ctx.showTypes || !displayType)
|
|
676
|
+
return cell;
|
|
677
|
+
return ((0, jsx_runtime_1.jsxs)(ScalarRow, { gapSize: 'tiny', verticalAlign: 'center', size: ctx.size, children: [cell, (0, jsx_runtime_1.jsx)(Tag_1.default, { size: ctx.size, flat: true, minimal: true, label: displayType, effect: { uppercase: true, spaced: 1, opacity: 0.6 }, className: 'reqore-data-view-type' })] }));
|
|
678
|
+
}
|
|
306
679
|
// Value chip: minimal + intent-tinted (so the type is colour-coded
|
|
307
680
|
// without shouting), weight bold. We always render with a border
|
|
308
681
|
// (flat={false}) — the panel's own `flat` prop affects the outer
|
|
@@ -361,17 +734,22 @@ var RecordTable = (0, react_1.memo)(function (_a) {
|
|
|
361
734
|
observer.observe(node);
|
|
362
735
|
return function () { return observer.disconnect(); };
|
|
363
736
|
}, []);
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
737
|
+
var siblingKeys = entries.map(function (_a) {
|
|
738
|
+
var k = _a[0];
|
|
739
|
+
return k;
|
|
740
|
+
});
|
|
741
|
+
return ((0, jsx_runtime_1.jsxs)(TableShell, { ref: shellRef, "$size": ctx.size, "$theme": theme, "$nested": depth > 0, className: 'reqore-data-view-record', children: [entries.map(function (_a, index) {
|
|
742
|
+
var _b;
|
|
743
|
+
var key = _a[0], item = _a[1];
|
|
744
|
+
var complex = (0, helpers_1.reqoreIsRecord)(ctx.envelope === false ? item : (0, helpers_1.reqoreUnwrapEnvelope)(item, ctx.envelope)) ||
|
|
745
|
+
(Array.isArray(ctx.envelope === false ? item : (0, helpers_1.reqoreUnwrapEnvelope)(item, ctx.envelope)) &&
|
|
746
|
+
!(ctx.inlineScalarArrays &&
|
|
747
|
+
(ctx.envelope === false
|
|
748
|
+
? item
|
|
749
|
+
: (0, helpers_1.reqoreUnwrapEnvelope)(item, ctx.envelope)).every(function (entry) { return isInlineableScalarValue(entry, ctx); })));
|
|
750
|
+
var rowPath = __spreadArray(__spreadArray([], path, true), [key], false);
|
|
751
|
+
return ((0, jsx_runtime_1.jsxs)(Row, { "$size": ctx.size, "$theme": theme, "$complex": complex, "$odd": index % 2 === 0, "$stacked": stacked, "$editable": ctx.editable, className: 'reqore-data-view-row', children: [ctx.editable ? ((0, jsx_runtime_1.jsx)(EditableKeyCell, { keyName: key, siblingKeys: siblingKeys, parentPath: path, ctx: ctx })) : ((0, jsx_runtime_1.jsx)(Tag_1.default, { size: ctx.size, flat: false, minimal: true, wrap: true, intent: ctx.keyIntent === null ? undefined : (_b = ctx.keyIntent) !== null && _b !== void 0 ? _b : 'info', color: ctx.keyColor, label: key, effect: { weight: 'bold' }, className: 'reqore-data-view-key' })), (0, jsx_runtime_1.jsx)(ValueCell, { "$size": ctx.size, "$theme": theme, "$complex": complex, className: 'reqore-data-view-value-cell', children: renderTree(item, ctx, theme, depth + 1, rowPath) }), ctx.editable ? ((0, jsx_runtime_1.jsx)(RowActions, { ctx: ctx, path: rowPath, ariaLabel: "Remove ".concat(key) })) : null] }, "".concat(path.join('.'), "-").concat(key)));
|
|
752
|
+
}), ctx.editable ? ((0, jsx_runtime_1.jsx)(AddEntryAffordance, { ctx: ctx, parentPath: path, context: { kind: 'record', existingKeys: siblingKeys } })) : null] }));
|
|
375
753
|
});
|
|
376
754
|
RecordTable.displayName = 'ReqoreDataView.RecordTable';
|
|
377
755
|
var renderTree = function (value, ctx, theme, depth, path) {
|
|
@@ -386,11 +764,19 @@ var renderTree = function (value, ctx, theme, depth, path) {
|
|
|
386
764
|
}
|
|
387
765
|
// Arrays.
|
|
388
766
|
if (Array.isArray(unwrapped)) {
|
|
389
|
-
|
|
767
|
+
// In editable mode, render every array item as its own row so the
|
|
768
|
+
// hover-revealed delete + `+ Add item` affordance has a place to
|
|
769
|
+
// live. The inline chip-row variant is for read-only density.
|
|
770
|
+
var allInlineable = !ctx.editable &&
|
|
771
|
+
ctx.inlineScalarArrays &&
|
|
772
|
+
unwrapped.every(function (item) { return isInlineableScalarValue(item, ctx); });
|
|
390
773
|
if (allInlineable) {
|
|
391
774
|
return ((0, jsx_runtime_1.jsxs)(ScalarRow, { size: ctx.size, gapSize: 'small', verticalAlign: 'center', children: [envelopeType ? ((0, jsx_runtime_1.jsx)(Tag_1.default, { size: ctx.size, minimal: true, flat: false, label: envelopeType, effect: { uppercase: true, spaced: 1, opacity: 0.6 }, className: 'reqore-data-view-type' })) : null, unwrapped.map(function (item, index) { return ((0, jsx_runtime_1.jsx)("span", { children: renderScalar(ctx.envelope === false ? item : (0, helpers_1.reqoreUnwrapEnvelope)(item, ctx.envelope), ctx.envelope === false ? undefined : (0, helpers_1.reqoreEnvelopeType)(item, ctx.envelope), ctx, __spreadArray(__spreadArray([], path, true), [String(index)], false)) }, "".concat(path.join('.'), "-").concat(index))); })] }));
|
|
392
775
|
}
|
|
393
|
-
var content = ((0, jsx_runtime_1.
|
|
776
|
+
var content = ((0, jsx_runtime_1.jsxs)(ArrayStack, { "$size": ctx.size, "$theme": theme, className: 'reqore-data-view-array', children: [unwrapped.map(function (item, index) {
|
|
777
|
+
var itemPath = __spreadArray(__spreadArray([], path, true), [String(index)], false);
|
|
778
|
+
return ((0, jsx_runtime_1.jsxs)(ArrayItem, { "$size": ctx.size, "$theme": theme, className: 'reqore-data-view-array-item reqore-data-view-row', children: [(0, jsx_runtime_1.jsxs)(ArrayItemContent, { children: [unwrapped.length > 1 ? ((0, jsx_runtime_1.jsx)(ArrayItemIndex, { "$size": ctx.size, "$theme": theme, children: index + 1 })) : null, renderTree(item, ctx, theme, depth + 1, itemPath)] }), ctx.editable ? ((0, jsx_runtime_1.jsx)(RowActions, { ctx: ctx, path: itemPath, ariaLabel: "Remove item ".concat(index + 1) })) : null] }, "".concat(path.join('.'), "-").concat(index)));
|
|
779
|
+
}), ctx.editable ? ((0, jsx_runtime_1.jsx)(AddEntryAffordance, { ctx: ctx, parentPath: path, context: { kind: 'array', length: unwrapped.length } })) : null] }));
|
|
394
780
|
if (depth === 0)
|
|
395
781
|
return content;
|
|
396
782
|
return ((0, jsx_runtime_1.jsx)(PreservedDetails, { initialOpen: depth < ctx.defaultExpandDepth, label: SECTION_LABEL('List', unwrapped.length), path: path, size: ctx.size, theme: theme, onToggle: ctx.onSectionToggle, children: content }));
|
|
@@ -407,9 +793,73 @@ var renderTree = function (value, ctx, theme, depth, path) {
|
|
|
407
793
|
};
|
|
408
794
|
exports.ReqoreDataView = (0, react_1.memo)((0, react_1.forwardRef)(function (_a, ref) {
|
|
409
795
|
var _b;
|
|
410
|
-
var data = _a.data, _c = _a.emptyText, emptyText = _c === void 0 ? 'No data.' : _c, _d = _a.collapsibleRoot, collapsibleRoot = _d === void 0 ? true : _d, _e = _a.defaultExpandDepth, defaultExpandDepth = _e === void 0 ? 2 : _e, _f = _a.showTypes, showTypes = _f === void 0 ? false : _f, _g = _a.inlineScalarArrays, inlineScalarArrays = _g === void 0 ? true : _g, _h = _a.envelope, envelope = _h === void 0 ? helpers_1.DEFAULT_ENVELOPE : _h, parseEmbedded = _a.parseEmbedded, parseDate = _a.parseDate, formatDate = _a.formatDate, onItemClick = _a.onItemClick, onSectionToggle = _a.onSectionToggle, keyColor = _a.keyColor, keyIntent = _a.keyIntent, _j = _a.size, size =
|
|
796
|
+
var data = _a.data, _c = _a.emptyText, emptyText = _c === void 0 ? 'No data.' : _c, _d = _a.collapsibleRoot, collapsibleRoot = _d === void 0 ? true : _d, _e = _a.defaultExpandDepth, defaultExpandDepth = _e === void 0 ? 2 : _e, _f = _a.showTypes, showTypes = _f === void 0 ? false : _f, _g = _a.inlineScalarArrays, inlineScalarArrays = _g === void 0 ? true : _g, _h = _a.envelope, envelope = _h === void 0 ? helpers_1.DEFAULT_ENVELOPE : _h, parseEmbedded = _a.parseEmbedded, parseDate = _a.parseDate, formatDate = _a.formatDate, onItemClick = _a.onItemClick, onSectionToggle = _a.onSectionToggle, keyColor = _a.keyColor, keyIntent = _a.keyIntent, _j = _a.editable, editable = _j === void 0 ? false : _j, onDataChange = _a.onDataChange, onValueChange = _a.onValueChange, onRemoveProperty = _a.onRemoveProperty, onRenameProperty = _a.onRenameProperty, onAddProperty = _a.onAddProperty, onChangeType = _a.onChangeType, _k = _a.size, size = _k === void 0 ? 'normal' : _k, customTheme = _a.customTheme, inheritCustomTheme = _a.inheritCustomTheme, intent = _a.intent, flat = _a.flat, panelProps = __rest(_a, ["data", "emptyText", "collapsibleRoot", "defaultExpandDepth", "showTypes", "inlineScalarArrays", "envelope", "parseEmbedded", "parseDate", "formatDate", "onItemClick", "onSectionToggle", "keyColor", "keyIntent", "editable", "onDataChange", "onValueChange", "onRemoveProperty", "onRenameProperty", "onAddProperty", "onChangeType", "size", "customTheme", "inheritCustomTheme", "intent", "flat"]);
|
|
411
797
|
var theme = (0, useTheme_1.useReqoreTheme)('main', customTheme, intent, undefined, inheritCustomTheme);
|
|
412
|
-
|
|
798
|
+
// In editable mode an empty `{}` or `[]` must still render the
|
|
799
|
+
// tree so the `+ Add property` / `+ Add item` affordance is
|
|
800
|
+
// reachable — otherwise a from-scratch build is impossible.
|
|
801
|
+
// Only fall back to the empty callout when read-only AND the
|
|
802
|
+
// value is genuinely empty.
|
|
803
|
+
var empty = !editable &&
|
|
804
|
+
!(0, helpers_1.reqoreHasStructuredValue)(data, envelope === false ? undefined : envelope);
|
|
805
|
+
var dataRef = (0, react_1.useRef)(data);
|
|
806
|
+
(0, react_1.useLayoutEffect)(function () {
|
|
807
|
+
dataRef.current = data;
|
|
808
|
+
}, [data]);
|
|
809
|
+
var commitScalar = (0, react_1.useCallback)(function (path, value) {
|
|
810
|
+
onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(path, value);
|
|
811
|
+
if (!onDataChange)
|
|
812
|
+
return;
|
|
813
|
+
var next = (0, helpers_1.reqoreSetAtPath)(dataRef.current, path, value);
|
|
814
|
+
onDataChange(next);
|
|
815
|
+
}, [onDataChange, onValueChange]);
|
|
816
|
+
var commitDelete = (0, react_1.useCallback)(function (path) {
|
|
817
|
+
onRemoveProperty === null || onRemoveProperty === void 0 ? void 0 : onRemoveProperty(path);
|
|
818
|
+
if (!onDataChange)
|
|
819
|
+
return;
|
|
820
|
+
var next = (0, helpers_1.reqoreDeleteAtPath)(dataRef.current, path);
|
|
821
|
+
onDataChange(next);
|
|
822
|
+
}, [onDataChange, onRemoveProperty]);
|
|
823
|
+
var commitRename = (0, react_1.useCallback)(function (parentPath, oldKey, newKey) {
|
|
824
|
+
onRenameProperty === null || onRenameProperty === void 0 ? void 0 : onRenameProperty(parentPath, oldKey, newKey);
|
|
825
|
+
if (!onDataChange)
|
|
826
|
+
return;
|
|
827
|
+
var next = (0, helpers_1.reqoreRenameKeyAtPath)(dataRef.current, parentPath, oldKey, newKey);
|
|
828
|
+
onDataChange(next);
|
|
829
|
+
}, [onDataChange, onRenameProperty]);
|
|
830
|
+
var commitAdd = (0, react_1.useCallback)(function (parentPath, keyOrIndex, initialValue) {
|
|
831
|
+
onAddProperty === null || onAddProperty === void 0 ? void 0 : onAddProperty(parentPath, keyOrIndex, initialValue);
|
|
832
|
+
if (!onDataChange)
|
|
833
|
+
return;
|
|
834
|
+
var next = (0, helpers_1.reqoreSetAtPath)(dataRef.current, __spreadArray(__spreadArray([], parentPath, true), [String(keyOrIndex)], false), initialValue);
|
|
835
|
+
onDataChange(next);
|
|
836
|
+
}, [onAddProperty, onDataChange]);
|
|
837
|
+
var commitTypeChange = (0, react_1.useCallback)(function (path, kind) {
|
|
838
|
+
onChangeType === null || onChangeType === void 0 ? void 0 : onChangeType(path, kind);
|
|
839
|
+
if (!onDataChange)
|
|
840
|
+
return;
|
|
841
|
+
// Read the current value at path, coerce it to the target
|
|
842
|
+
// kind, and re-emit the tree. The lookup walks the same
|
|
843
|
+
// path the set will use, so a missing path is a no-op.
|
|
844
|
+
var current = dataRef.current;
|
|
845
|
+
for (var _i = 0, path_1 = path; _i < path_1.length; _i++) {
|
|
846
|
+
var segment = path_1[_i];
|
|
847
|
+
if (current == null)
|
|
848
|
+
return;
|
|
849
|
+
if (Array.isArray(current)) {
|
|
850
|
+
var index = Number.parseInt(segment, 10);
|
|
851
|
+
current = Number.isNaN(index) ? undefined : current[index];
|
|
852
|
+
}
|
|
853
|
+
else if ((0, helpers_1.reqoreIsRecord)(current)) {
|
|
854
|
+
current = current[segment];
|
|
855
|
+
}
|
|
856
|
+
else {
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
var next = (0, helpers_1.reqoreSetAtPath)(dataRef.current, path, (0, helpers_1.reqoreCoerceValueToKind)(current, kind));
|
|
861
|
+
onDataChange(next);
|
|
862
|
+
}, [onChangeType, onDataChange]);
|
|
413
863
|
var ctx = {
|
|
414
864
|
envelope: envelope,
|
|
415
865
|
parseEmbedded: parseEmbedded,
|
|
@@ -422,6 +872,12 @@ exports.ReqoreDataView = (0, react_1.memo)((0, react_1.forwardRef)(function (_a,
|
|
|
422
872
|
onSectionToggle: onSectionToggle,
|
|
423
873
|
keyColor: keyColor,
|
|
424
874
|
keyIntent: keyIntent,
|
|
875
|
+
editable: editable,
|
|
876
|
+
commitScalar: editable ? commitScalar : undefined,
|
|
877
|
+
commitDelete: editable ? commitDelete : undefined,
|
|
878
|
+
commitRename: editable ? commitRename : undefined,
|
|
879
|
+
commitAdd: editable ? commitAdd : undefined,
|
|
880
|
+
commitTypeChange: editable ? commitTypeChange : undefined,
|
|
425
881
|
};
|
|
426
882
|
var body = empty ? ((0, jsx_runtime_1.jsx)(Paragraph_1.ReqoreP, { size: size, effect: { opacity: 0.65 }, children: emptyText })) : collapsibleRoot ? ((0, jsx_runtime_1.jsx)(PreservedDetails, { initialOpen: true, label: Array.isArray(data)
|
|
427
883
|
? SECTION_LABEL('List', data.length)
|
|
@@ -433,13 +889,17 @@ exports.ReqoreDataView = (0, react_1.memo)((0, react_1.forwardRef)(function (_a,
|
|
|
433
889
|
exports.ReqoreDataView.displayName = 'ReqoreDataView';
|
|
434
890
|
var helpers_2 = require("./helpers");
|
|
435
891
|
Object.defineProperty(exports, "DEFAULT_ENVELOPE", { enumerable: true, get: function () { return helpers_2.DEFAULT_ENVELOPE; } });
|
|
892
|
+
Object.defineProperty(exports, "reqoreCoerceValueToKind", { enumerable: true, get: function () { return helpers_2.reqoreCoerceValueToKind; } });
|
|
436
893
|
Object.defineProperty(exports, "reqoreDataValueIntent", { enumerable: true, get: function () { return helpers_2.reqoreDataValueIntent; } });
|
|
437
894
|
Object.defineProperty(exports, "reqoreDataValueKind", { enumerable: true, get: function () { return helpers_2.reqoreDataValueKind; } });
|
|
895
|
+
Object.defineProperty(exports, "reqoreDeleteAtPath", { enumerable: true, get: function () { return helpers_2.reqoreDeleteAtPath; } });
|
|
438
896
|
Object.defineProperty(exports, "reqoreEnvelopeType", { enumerable: true, get: function () { return helpers_2.reqoreEnvelopeType; } });
|
|
439
897
|
Object.defineProperty(exports, "reqoreFormatScalar", { enumerable: true, get: function () { return helpers_2.reqoreFormatScalar; } });
|
|
440
898
|
Object.defineProperty(exports, "reqoreHasStructuredValue", { enumerable: true, get: function () { return helpers_2.reqoreHasStructuredValue; } });
|
|
441
899
|
Object.defineProperty(exports, "reqoreIsEnvelope", { enumerable: true, get: function () { return helpers_2.reqoreIsEnvelope; } });
|
|
442
900
|
Object.defineProperty(exports, "reqoreIsRecord", { enumerable: true, get: function () { return helpers_2.reqoreIsRecord; } });
|
|
901
|
+
Object.defineProperty(exports, "reqoreRenameKeyAtPath", { enumerable: true, get: function () { return helpers_2.reqoreRenameKeyAtPath; } });
|
|
902
|
+
Object.defineProperty(exports, "reqoreSetAtPath", { enumerable: true, get: function () { return helpers_2.reqoreSetAtPath; } });
|
|
443
903
|
Object.defineProperty(exports, "reqoreUnwrapEnvelope", { enumerable: true, get: function () { return helpers_2.reqoreUnwrapEnvelope; } });
|
|
444
|
-
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6, templateObject_7, templateObject_8, templateObject_9, templateObject_10, templateObject_11, templateObject_12;
|
|
904
|
+
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6, templateObject_7, templateObject_8, templateObject_9, templateObject_10, templateObject_11, templateObject_12, templateObject_13, templateObject_14, templateObject_15, templateObject_16;
|
|
445
905
|
//# sourceMappingURL=index.js.map
|