@qoretechnologies/reqore 0.69.5 → 0.70.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/.tasks/EDITABLE_DATAVIEW.md +171 -0
  2. package/dist/components/Button/index.d.ts +14 -0
  3. package/dist/components/Button/index.d.ts.map +1 -1
  4. package/dist/components/Button/index.js +20 -3
  5. package/dist/components/Button/index.js.map +1 -1
  6. package/dist/components/DataView/helpers.d.ts +41 -0
  7. package/dist/components/DataView/helpers.d.ts.map +1 -1
  8. package/dist/components/DataView/helpers.js +189 -1
  9. package/dist/components/DataView/helpers.js.map +1 -1
  10. package/dist/components/DataView/index.d.ts +49 -2
  11. package/dist/components/DataView/index.d.ts.map +1 -1
  12. package/dist/components/DataView/index.js +485 -25
  13. package/dist/components/DataView/index.js.map +1 -1
  14. package/dist/components/DatePicker/index.d.ts.map +1 -1
  15. package/dist/components/DatePicker/index.js +2 -2
  16. package/dist/components/DatePicker/index.js.map +1 -1
  17. package/dist/components/Input/index.d.ts +6 -0
  18. package/dist/components/Input/index.d.ts.map +1 -1
  19. package/dist/components/Input/index.js +25 -10
  20. package/dist/components/Input/index.js.map +1 -1
  21. package/dist/components/KeyboardShortcut/index.d.ts +33 -0
  22. package/dist/components/KeyboardShortcut/index.d.ts.map +1 -0
  23. package/dist/components/KeyboardShortcut/index.js +69 -0
  24. package/dist/components/KeyboardShortcut/index.js.map +1 -0
  25. package/dist/components/StackedBar/index.d.ts +80 -0
  26. package/dist/components/StackedBar/index.d.ts.map +1 -0
  27. package/dist/components/StackedBar/index.js +209 -0
  28. package/dist/components/StackedBar/index.js.map +1 -0
  29. package/dist/components/Textarea/index.d.ts +5 -0
  30. package/dist/components/Textarea/index.d.ts.map +1 -1
  31. package/dist/components/Textarea/index.js +12 -3
  32. package/dist/components/Textarea/index.js.map +1 -1
  33. package/dist/containers/ReqoreProvider.d.ts.map +1 -1
  34. package/dist/containers/ReqoreProvider.js +3 -1
  35. package/dist/containers/ReqoreProvider.js.map +1 -1
  36. package/dist/containers/UIProvider.d.ts +1 -1
  37. package/dist/containers/UIProvider.d.ts.map +1 -1
  38. package/dist/containers/UIProvider.js.map +1 -1
  39. package/dist/context/ReqoreContext.d.ts +8 -0
  40. package/dist/context/ReqoreContext.d.ts.map +1 -1
  41. package/dist/context/ReqoreContext.js +1 -0
  42. package/dist/context/ReqoreContext.js.map +1 -1
  43. package/dist/helpers/shortcuts.d.ts +35 -0
  44. package/dist/helpers/shortcuts.d.ts.map +1 -0
  45. package/dist/helpers/shortcuts.js +152 -0
  46. package/dist/helpers/shortcuts.js.map +1 -0
  47. package/dist/index.d.ts +6 -1
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +17 -3
  50. package/dist/index.js.map +1 -1
  51. package/package.json +3 -2
  52. 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
- return $complex || $stacked
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 /* Same depth model as nested TableShell \u2014 darker overlay, neutral\n hairline border on three sides + a slightly more visible accent\n on the left edge to read as a nested chunk. */\n border: 1px solid ", ";\n border-left: 2px solid ", ";\n border-radius: ", "px;\n /* Same depth as a nested TableShell (0.45) \u2014 an array item *is* a\n nested chunk. */\n background: rgba(0, 0, 0, 0.45);\n"], ["\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 /* Same depth model as nested TableShell \u2014 darker overlay, neutral\n hairline border on three sides + a slightly more visible accent\n on the left edge to read as a nested chunk. */\n border: 1px solid ", ";\n border-left: 2px solid ", ";\n border-radius: ", "px;\n /* Same depth as a nested TableShell (0.45) \u2014 an array item *is* a\n nested chunk. */\n background: rgba(0, 0, 0, 0.45);\n"])), function (_a) {
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
- var ArrayItemIndex = styled_components_1.default.span(templateObject_9 || (templateObject_9 = __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) {
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)(templateObject_10 || (templateObject_10 = __makeTemplateObject(["\n flex-wrap: wrap;\n"], ["\n flex-wrap: wrap;\n"])));
215
- var SectionDetails = styled_components_1.default.details(templateObject_11 || (templateObject_11 = __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) {
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(templateObject_12 || (templateObject_12 = __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) {
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
- return ((0, jsx_runtime_1.jsx)(TableShell, { ref: shellRef, "$size": ctx.size, "$theme": theme, "$nested": depth > 0, className: 'reqore-data-view-record', children: entries.map(function (_a, index) {
365
- var _b;
366
- var key = _a[0], item = _a[1];
367
- var complex = (0, helpers_1.reqoreIsRecord)(ctx.envelope === false ? item : (0, helpers_1.reqoreUnwrapEnvelope)(item, ctx.envelope)) ||
368
- (Array.isArray(ctx.envelope === false ? item : (0, helpers_1.reqoreUnwrapEnvelope)(item, ctx.envelope)) &&
369
- !(ctx.inlineScalarArrays &&
370
- (ctx.envelope === false
371
- ? item
372
- : (0, helpers_1.reqoreUnwrapEnvelope)(item, ctx.envelope)).every(function (entry) { return isInlineableScalarValue(entry, ctx); })));
373
- return ((0, jsx_runtime_1.jsxs)(Row, { "$size": ctx.size, "$theme": theme, "$complex": complex, "$odd": index % 2 === 0, "$stacked": stacked, className: 'reqore-data-view-row', 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: 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, __spreadArray(__spreadArray([], path, true), [key], false)) })] }, "".concat(path.join('.'), "-").concat(key)));
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
- var allInlineable = ctx.inlineScalarArrays && unwrapped.every(function (item) { return isInlineableScalarValue(item, ctx); });
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.jsx)(ArrayStack, { "$size": ctx.size, "$theme": theme, className: 'reqore-data-view-array', children: unwrapped.map(function (item, index) { return ((0, jsx_runtime_1.jsxs)(ArrayItem, { "$size": ctx.size, "$theme": theme, className: 'reqore-data-view-array-item', 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, __spreadArray(__spreadArray([], path, true), [String(index)], false))] }, "".concat(path.join('.'), "-").concat(index))); }) }));
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 = _j === void 0 ? 'normal' : _j, 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", "size", "customTheme", "inheritCustomTheme", "intent", "flat"]);
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
- var empty = !(0, helpers_1.reqoreHasStructuredValue)(data, envelope === false ? undefined : envelope);
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