@script-it/json-views-react 0.1.0-beta.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.
- package/LICENSE +21 -0
- package/README.md +301 -0
- package/THIRD_PARTY_NOTICES.txt +4917 -0
- package/dist/browser-device.d.ts +21 -0
- package/dist/browser-device.js +22 -0
- package/dist/file-content-edit-state.d.ts +10 -0
- package/dist/file-content-edit-state.js +1 -0
- package/dist/file-content-view.d.ts +8 -0
- package/dist/file-content-view.js +7 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +8 -0
- package/dist/json/copy-json.d.ts +15 -0
- package/dist/json/copy-json.js +52 -0
- package/dist/json/html-preview.d.ts +5 -0
- package/dist/json/html-preview.js +12 -0
- package/dist/json/html-view/native-control.d.ts +44 -0
- package/dist/json/html-view/native-control.js +96 -0
- package/dist/json/html-view/settings.d.ts +2 -0
- package/dist/json/html-view/settings.js +58 -0
- package/dist/json/html-view/template.d.ts +12 -0
- package/dist/json/html-view/template.js +55 -0
- package/dist/json/html-view.d.ts +9 -0
- package/dist/json/html-view.js +163 -0
- package/dist/json/json-content.d.ts +61 -0
- package/dist/json/json-content.js +433 -0
- package/dist/json/json-source-editor.d.ts +36 -0
- package/dist/json/json-source-editor.js +203 -0
- package/dist/json/json-view.d.ts +3 -0
- package/dist/json/json-view.js +322 -0
- package/dist/json/kanban-view.d.ts +20 -0
- package/dist/json/kanban-view.js +328 -0
- package/dist/json/long-text.d.ts +3 -0
- package/dist/json/long-text.js +6 -0
- package/dist/json/record-view.d.ts +38 -0
- package/dist/json/record-view.js +85 -0
- package/dist/json/row-mutations.d.ts +7 -0
- package/dist/json/row-mutations.js +93 -0
- package/dist/json/schema-value.d.ts +57 -0
- package/dist/json/schema-value.js +294 -0
- package/dist/json/source-default.d.ts +1 -0
- package/dist/json/source-default.js +1 -0
- package/dist/json/source-edit-capabilities.d.ts +8 -0
- package/dist/json/source-edit-capabilities.js +22 -0
- package/dist/json/source-literals.d.ts +15 -0
- package/dist/json/source-literals.js +24 -0
- package/dist/json/source-recovery.d.ts +32 -0
- package/dist/json/source-recovery.js +38 -0
- package/dist/json/source-selection.d.ts +3 -0
- package/dist/json/source-selection.js +16 -0
- package/dist/json/table-view.d.ts +20 -0
- package/dist/json/table-view.js +300 -0
- package/dist/json/use-kanban-card-drag.d.ts +13 -0
- package/dist/json/use-kanban-card-drag.js +255 -0
- package/dist/json/use-kanban-column-drag.d.ts +14 -0
- package/dist/json/use-kanban-column-drag.js +179 -0
- package/dist/json/view-diagnostics.d.ts +4 -0
- package/dist/json/view-diagnostics.js +26 -0
- package/dist/json/view-model.d.ts +27 -0
- package/dist/json/view-model.js +180 -0
- package/dist/json/view-save-status.d.ts +12 -0
- package/dist/json/view-save-status.js +38 -0
- package/dist/json/view-settings.d.ts +36 -0
- package/dist/json/view-settings.js +661 -0
- package/dist/json/view-types.d.ts +47 -0
- package/dist/json/view-types.js +4 -0
- package/dist/json/viewers/general/general-json-view.d.ts +46 -0
- package/dist/json/viewers/general/general-json-view.js +163 -0
- package/dist/json/viewers/general/json-flatten.d.ts +33 -0
- package/dist/json/viewers/general/json-flatten.js +51 -0
- package/dist/json/viewers/general/json-node-view.d.ts +43 -0
- package/dist/json/viewers/general/json-node-view.js +215 -0
- package/dist/lib/clipboard.d.ts +1 -0
- package/dist/lib/clipboard.js +24 -0
- package/dist/lib/cn.d.ts +2 -0
- package/dist/lib/cn.js +5 -0
- package/dist/lib/file-data.d.ts +7 -0
- package/dist/lib/file-data.js +5 -0
- package/dist/lib/floating-portal-selectors.d.ts +4 -0
- package/dist/lib/floating-portal-selectors.js +4 -0
- package/dist/lib/time.d.ts +24 -0
- package/dist/lib/time.js +60 -0
- package/dist/lib/ui-size.d.ts +28 -0
- package/dist/lib/ui-size.js +39 -0
- package/dist/lib/use-anchored-position.d.ts +5 -0
- package/dist/lib/use-anchored-position.js +65 -0
- package/dist/lib/use-dismiss.d.ts +31 -0
- package/dist/lib/use-dismiss.js +65 -0
- package/dist/primitives/boolean-toggle.d.ts +10 -0
- package/dist/primitives/boolean-toggle.js +11 -0
- package/dist/primitives/button.d.ts +11 -0
- package/dist/primitives/button.js +34 -0
- package/dist/primitives/checkbox.d.ts +4 -0
- package/dist/primitives/checkbox.js +8 -0
- package/dist/primitives/choice-control.d.ts +29 -0
- package/dist/primitives/choice-control.js +131 -0
- package/dist/primitives/dialog.d.ts +29 -0
- package/dist/primitives/dialog.js +25 -0
- package/dist/primitives/dropdown-menu.d.ts +37 -0
- package/dist/primitives/dropdown-menu.js +39 -0
- package/dist/primitives/inline-feedback-action.d.ts +13 -0
- package/dist/primitives/inline-feedback-action.js +6 -0
- package/dist/primitives/menu-select.d.ts +12 -0
- package/dist/primitives/menu-select.js +7 -0
- package/dist/primitives/multi-select.d.ts +18 -0
- package/dist/primitives/multi-select.js +7 -0
- package/dist/primitives/number-input.d.ts +10 -0
- package/dist/primitives/number-input.js +8 -0
- package/dist/primitives/option-pill.d.ts +13 -0
- package/dist/primitives/option-pill.js +50 -0
- package/dist/primitives/tabs.d.ts +7 -0
- package/dist/primitives/tabs.js +12 -0
- package/dist/primitives/textarea.d.ts +4 -0
- package/dist/primitives/textarea.js +8 -0
- package/dist/primitives/tooltip.d.ts +31 -0
- package/dist/primitives/tooltip.js +37 -0
- package/dist/standalone.css +113 -0
- package/dist/structured-data/atomic-value-editor.d.ts +33 -0
- package/dist/structured-data/atomic-value-editor.js +195 -0
- package/dist/structured-data/atomic-value.d.ts +3 -0
- package/dist/structured-data/atomic-value.js +6 -0
- package/dist/structured-data/column-controls.d.ts +21 -0
- package/dist/structured-data/column-controls.js +180 -0
- package/dist/structured-data/copy-json-action.d.ts +10 -0
- package/dist/structured-data/copy-json-action.js +87 -0
- package/dist/structured-data/delete-row-action.d.ts +10 -0
- package/dist/structured-data/delete-row-action.js +37 -0
- package/dist/structured-data/edit-base.d.ts +3 -0
- package/dist/structured-data/edit-base.js +8 -0
- package/dist/structured-data/filter-value.d.ts +2 -0
- package/dist/structured-data/filter-value.js +28 -0
- package/dist/structured-data/row-selection-icon.d.ts +9 -0
- package/dist/structured-data/row-selection-icon.js +6 -0
- package/dist/structured-data/structured-cell-fill-context.d.ts +6 -0
- package/dist/structured-data/structured-cell-fill-context.js +7 -0
- package/dist/structured-data/structured-data-content.d.ts +1 -0
- package/dist/structured-data/structured-data-content.js +1 -0
- package/dist/structured-data/table-types.d.ts +108 -0
- package/dist/structured-data/table-types.js +1 -0
- package/dist/structured-data/use-metadata-persistence.d.ts +15 -0
- package/dist/structured-data/use-metadata-persistence.js +18 -0
- package/dist/structured-data/use-optimistic-text-document.d.ts +22 -0
- package/dist/structured-data/use-optimistic-text-document.js +30 -0
- package/dist/structured-data/value-cell.d.ts +15 -0
- package/dist/structured-data/value-cell.js +81 -0
- package/dist/styles.css +2 -0
- package/dist/surface.d.ts +14 -0
- package/dist/surface.js +73 -0
- package/dist/tabular-data-view.d.ts +5 -0
- package/dist/tabular-data-view.js +493 -0
- package/dist/viewer-state.d.ts +72 -0
- package/dist/viewer-state.js +79 -0
- package/dist/widget-registry.d.ts +60 -0
- package/dist/widget-registry.js +126 -0
- package/dist/widgets/boolean-widget.d.ts +2 -0
- package/dist/widgets/boolean-widget.js +15 -0
- package/dist/widgets/date-picker-widget.d.ts +18 -0
- package/dist/widgets/date-picker-widget.js +265 -0
- package/dist/widgets/dropdown-widget.d.ts +10 -0
- package/dist/widgets/dropdown-widget.js +19 -0
- package/dist/widgets/multi-select-widget.d.ts +11 -0
- package/dist/widgets/multi-select-widget.js +46 -0
- package/dist/widgets/number-widget.d.ts +2 -0
- package/dist/widgets/number-widget.js +19 -0
- package/dist/widgets/read-only-field.d.ts +36 -0
- package/dist/widgets/read-only-field.js +39 -0
- package/dist/widgets/text-widget.d.ts +2 -0
- package/dist/widgets/text-widget.js +19 -0
- package/dist/widgets/textarea-widget.d.ts +2 -0
- package/dist/widgets/textarea-widget.js +34 -0
- package/dist/widgets/types.d.ts +53 -0
- package/dist/widgets/types.js +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import yaml, { JSON_SCHEMA } from 'js-yaml';
|
|
3
|
+
import { MultiSelect } from '../primitives/multi-select.js';
|
|
4
|
+
import { ReadOnlyChip, ReadOnlyEmpty } from './read-only-field.js';
|
|
5
|
+
function parseSelectedValues(value) {
|
|
6
|
+
try {
|
|
7
|
+
if (value.startsWith('[')) {
|
|
8
|
+
const parsed = JSON.parse(value);
|
|
9
|
+
return Array.isArray(parsed) ? parsed.map(String) : [];
|
|
10
|
+
}
|
|
11
|
+
if (value.startsWith('-')) {
|
|
12
|
+
const parsed = yaml.load(value, { schema: JSON_SCHEMA });
|
|
13
|
+
if (Array.isArray(parsed)) {
|
|
14
|
+
return parsed.map(String);
|
|
15
|
+
}
|
|
16
|
+
return value ? [value] : [];
|
|
17
|
+
}
|
|
18
|
+
if (value.includes(',')) {
|
|
19
|
+
return value.split(',').map((s) => s.trim()).filter(Boolean);
|
|
20
|
+
}
|
|
21
|
+
return value ? [value] : [];
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return value ? [value] : [];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function optionValue(option) {
|
|
28
|
+
return typeof option === 'object' ? option.value : String(option);
|
|
29
|
+
}
|
|
30
|
+
function optionLabel(option) {
|
|
31
|
+
return typeof option === 'object' ? option.label : String(option);
|
|
32
|
+
}
|
|
33
|
+
export function MultiSelectWidget({ value, onChange, onDirectSave, onBlur, ariaLabel, ariaDescribedBy, invalid = false, options: optionOverrides, profile = 'plain', creatable = false, openOnMount, onDismiss, onOptionColorChange, readOnly = false, disabled = false, uiHint, }) {
|
|
34
|
+
const options = optionOverrides ?? (uiHint && 'options' in uiHint && Array.isArray(uiHint.options)
|
|
35
|
+
? uiHint.options
|
|
36
|
+
: []);
|
|
37
|
+
const selectedValues = parseSelectedValues(value);
|
|
38
|
+
if (readOnly && profile === 'plain') {
|
|
39
|
+
return (_jsx("div", { "aria-readonly": "true", children: selectedValues.length > 0 ? (_jsx("div", { className: "flex flex-wrap gap-2", children: selectedValues.map((selected, idx) => (_jsx(ReadOnlyChip, { emphasis: true, className: "px-3 py-1.5", children: optionLabel(options.find((option) => optionValue(option) === selected) ?? selected) }, idx))) })) : (_jsx(ReadOnlyEmpty, {})) }));
|
|
40
|
+
}
|
|
41
|
+
const handleChange = (next) => {
|
|
42
|
+
onChange(JSON.stringify(next));
|
|
43
|
+
onDirectSave?.(next);
|
|
44
|
+
};
|
|
45
|
+
return (_jsx(MultiSelect, { "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, invalid: invalid, openOnMount: openOnMount, onDismiss: onDismiss, value: selectedValues, onChange: handleChange, onSelectionBlur: onBlur, options: options, disabled: disabled, readOnly: readOnly, profile: profile, creatable: creatable, onOptionColorChange: onOptionColorChange }));
|
|
46
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { NumberInput } from '../primitives/number-input.js';
|
|
3
|
+
import { READONLY_SURFACE_CLASSES } from './read-only-field.js';
|
|
4
|
+
import { cn } from '../lib/cn.js';
|
|
5
|
+
export function NumberWidget({ value, onChange, onBlur, ariaLabel, ariaDescribedBy, invalid = false, readOnly = false, disabled = false, surface = 'default', metadata, uiHint, }) {
|
|
6
|
+
const uiHintType = uiHint?.type;
|
|
7
|
+
const min = uiHint && uiHintType === 'number' && 'min' in uiHint && typeof uiHint.min === 'number'
|
|
8
|
+
? uiHint.min
|
|
9
|
+
: undefined;
|
|
10
|
+
const max = uiHint && uiHintType === 'number' && 'max' in uiHint && typeof uiHint.max === 'number'
|
|
11
|
+
? uiHint.max
|
|
12
|
+
: undefined;
|
|
13
|
+
const step = uiHint && uiHintType === 'number' && 'step' in uiHint && typeof uiHint.step === 'number'
|
|
14
|
+
? uiHint.step
|
|
15
|
+
: metadata?.type === 'float'
|
|
16
|
+
? 0.01
|
|
17
|
+
: 1;
|
|
18
|
+
return (_jsx(NumberInput, { autoFocus: !readOnly, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, "aria-invalid": invalid || undefined, value: value, onChange: onChange, onBlur: onBlur, min: min, max: max, step: step, readOnly: readOnly, disabled: disabled, placeholder: readOnly ? '—' : 'Enter a number', className: cn(surface === 'inline' && !readOnly && 'h-7 rounded-sm border-transparent bg-transparent px-1 py-0 text-xs shadow-none outline-none hover:bg-accent/40 focus:border-transparent focus:ring-1 focus:ring-inset focus:ring-ring', readOnly && READONLY_SURFACE_CLASSES, invalid && 'border-destructive focus:border-destructive focus:ring-destructive/20') }));
|
|
19
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Shared read-only presentation for the input-editor widgets.
|
|
4
|
+
*
|
|
5
|
+
* Read-only is a mode of each widget, not a substitute component — these are
|
|
6
|
+
* style helpers the widgets compose in their `readOnly` branch, never entries
|
|
7
|
+
* in the widget registry. The look is built entirely from semantic tokens
|
|
8
|
+
* (`muted` / `border` / `foreground`) so it themes in light and dark.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Muted, non-interactive boxed field for read-only widgets that render their
|
|
12
|
+
* own container (text, dropdown, date). Matches the editable field footprint
|
|
13
|
+
* (`w-full rounded-md px-3 py-2 text-sm`) so the layout doesn't shift.
|
|
14
|
+
*/
|
|
15
|
+
export declare const READONLY_FIELD_CLASSES = "w-full rounded-md border border-border bg-muted px-3 py-2 text-sm text-foreground focus:outline-none";
|
|
16
|
+
/**
|
|
17
|
+
* Colour-only override appended to a primitive's `className` when the primitive
|
|
18
|
+
* keeps its own layout but must present as read-only (textarea, number). Relies
|
|
19
|
+
* on the primitives merging `className` last via `cn`, so these win over the
|
|
20
|
+
* editable `border-border bg-card focus:ring-ring` defaults.
|
|
21
|
+
*/
|
|
22
|
+
export declare const READONLY_SURFACE_CLASSES = "cursor-default border-border bg-muted text-foreground focus:border-border focus:ring-0";
|
|
23
|
+
/** The neutral placeholder shown where a read-only value is empty. */
|
|
24
|
+
export declare const READONLY_EMPTY = "\u2014";
|
|
25
|
+
/** Renders `—` in muted ink for an empty read-only value. */
|
|
26
|
+
export declare function ReadOnlyEmpty(): import("react").JSX.Element;
|
|
27
|
+
/**
|
|
28
|
+
* Muted, non-interactive chip used by the boolean and multi-select read-only
|
|
29
|
+
* renders. `emphasis` marks a selected option (a filled-but-muted pill) versus
|
|
30
|
+
* an unselected one (quiet outline).
|
|
31
|
+
*/
|
|
32
|
+
export declare function ReadOnlyChip({ children, emphasis, className, }: {
|
|
33
|
+
children: ReactNode;
|
|
34
|
+
emphasis?: boolean;
|
|
35
|
+
className?: string;
|
|
36
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '../lib/cn.js';
|
|
3
|
+
/**
|
|
4
|
+
* Shared read-only presentation for the input-editor widgets.
|
|
5
|
+
*
|
|
6
|
+
* Read-only is a mode of each widget, not a substitute component — these are
|
|
7
|
+
* style helpers the widgets compose in their `readOnly` branch, never entries
|
|
8
|
+
* in the widget registry. The look is built entirely from semantic tokens
|
|
9
|
+
* (`muted` / `border` / `foreground`) so it themes in light and dark.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Muted, non-interactive boxed field for read-only widgets that render their
|
|
13
|
+
* own container (text, dropdown, date). Matches the editable field footprint
|
|
14
|
+
* (`w-full rounded-md px-3 py-2 text-sm`) so the layout doesn't shift.
|
|
15
|
+
*/
|
|
16
|
+
export const READONLY_FIELD_CLASSES = 'w-full rounded-md border border-border bg-muted px-3 py-2 text-sm text-foreground focus:outline-none';
|
|
17
|
+
/**
|
|
18
|
+
* Colour-only override appended to a primitive's `className` when the primitive
|
|
19
|
+
* keeps its own layout but must present as read-only (textarea, number). Relies
|
|
20
|
+
* on the primitives merging `className` last via `cn`, so these win over the
|
|
21
|
+
* editable `border-border bg-card focus:ring-ring` defaults.
|
|
22
|
+
*/
|
|
23
|
+
export const READONLY_SURFACE_CLASSES = 'cursor-default border-border bg-muted text-foreground focus:border-border focus:ring-0';
|
|
24
|
+
/** The neutral placeholder shown where a read-only value is empty. */
|
|
25
|
+
export const READONLY_EMPTY = '—';
|
|
26
|
+
/** Renders `—` in muted ink for an empty read-only value. */
|
|
27
|
+
export function ReadOnlyEmpty() {
|
|
28
|
+
return _jsx("span", { className: "text-muted-foreground", children: READONLY_EMPTY });
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Muted, non-interactive chip used by the boolean and multi-select read-only
|
|
32
|
+
* renders. `emphasis` marks a selected option (a filled-but-muted pill) versus
|
|
33
|
+
* an unselected one (quiet outline).
|
|
34
|
+
*/
|
|
35
|
+
export function ReadOnlyChip({ children, emphasis = false, className, }) {
|
|
36
|
+
return (_jsx("span", { className: cn('inline-flex items-center rounded-md border px-2.5 py-1 text-sm', emphasis
|
|
37
|
+
? 'border-border bg-muted text-foreground'
|
|
38
|
+
: 'border-border bg-transparent text-muted-foreground', className), children: children }));
|
|
39
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { READONLY_FIELD_CLASSES } from './read-only-field.js';
|
|
3
|
+
import { cn } from '../lib/cn.js';
|
|
4
|
+
const EDITABLE_CLASSES = 'w-full rounded-md border border-border bg-card px-3 py-2 text-sm transition-colors focus:border-transparent focus:outline-none focus:ring-2 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50';
|
|
5
|
+
export function TextWidget({ value, onChange, onBlur, ariaLabel, ariaDescribedBy, invalid = false, readOnly = false, disabled = false, surface = 'default', uiHint, }) {
|
|
6
|
+
const placeholder = readOnly
|
|
7
|
+
? '—'
|
|
8
|
+
: uiHint?.type === 'text' &&
|
|
9
|
+
'placeholder' in uiHint &&
|
|
10
|
+
typeof uiHint.placeholder === 'string' &&
|
|
11
|
+
uiHint.placeholder.length > 0
|
|
12
|
+
? uiHint.placeholder
|
|
13
|
+
: 'Enter value';
|
|
14
|
+
return (_jsx("input", { autoFocus: !readOnly, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, "aria-invalid": invalid || undefined, type: "text", value: value, onChange: (e) => onChange(e.target.value), onBlur: onBlur, readOnly: readOnly, disabled: disabled, placeholder: placeholder, className: cn(readOnly
|
|
15
|
+
? READONLY_FIELD_CLASSES
|
|
16
|
+
: surface === 'inline'
|
|
17
|
+
? 'h-7 w-full rounded-sm border border-transparent bg-transparent px-1 py-0 text-xs outline-none hover:bg-accent/40 focus:border-transparent focus:ring-1 focus:ring-inset focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50'
|
|
18
|
+
: EDITABLE_CLASSES, invalid && 'border-destructive focus:border-destructive focus:ring-destructive/20') }));
|
|
19
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useLayoutEffect, useRef } from 'react';
|
|
3
|
+
import { Textarea } from '../primitives/textarea.js';
|
|
4
|
+
import { cn } from '../lib/cn.js';
|
|
5
|
+
import { READONLY_SURFACE_CLASSES } from './read-only-field.js';
|
|
6
|
+
export function TextareaWidget({ value, onChange, onBlur, ariaLabel, ariaDescribedBy, invalid = false, minHeight, autoSize = false, readOnly = false, disabled = false, surface = 'default', metadata, uiHint, }) {
|
|
7
|
+
const textareaRef = useRef(null);
|
|
8
|
+
const isObjectOrArray = metadata?.type === 'array';
|
|
9
|
+
const rows = isObjectOrArray ? 8 : 4;
|
|
10
|
+
const placeholder = readOnly
|
|
11
|
+
? '—'
|
|
12
|
+
: isObjectOrArray
|
|
13
|
+
? 'Enter YAML'
|
|
14
|
+
: uiHint &&
|
|
15
|
+
'placeholder' in uiHint &&
|
|
16
|
+
typeof uiHint.placeholder === 'string' &&
|
|
17
|
+
uiHint.placeholder.length > 0
|
|
18
|
+
? uiHint.placeholder
|
|
19
|
+
: 'Enter text';
|
|
20
|
+
useLayoutEffect(() => {
|
|
21
|
+
if (!autoSize || !textareaRef.current)
|
|
22
|
+
return;
|
|
23
|
+
const textarea = textareaRef.current;
|
|
24
|
+
textarea.style.height = 'auto';
|
|
25
|
+
textarea.style.height = `${Math.max(minHeight ?? 0, textarea.scrollHeight)}px`;
|
|
26
|
+
if (!readOnly)
|
|
27
|
+
textarea.focus({ preventScroll: true });
|
|
28
|
+
}, [autoSize, minHeight, readOnly, value]);
|
|
29
|
+
return (_jsx(Textarea, { ref: textareaRef, autoFocus: !readOnly && !autoSize, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, "aria-invalid": invalid || undefined, value: value, onChange: (e) => onChange(e.target.value), onBlur: onBlur, rows: rows, readOnly: readOnly, disabled: disabled, placeholder: placeholder, style: minHeight ? { minHeight } : undefined,
|
|
30
|
+
// Soft wrapping already folds prose at spaces; `break-words` additionally
|
|
31
|
+
// folds a token too long to fit on its own — a URL, a long `${{ }}`
|
|
32
|
+
// expression — instead of letting it scroll out of the card sideways.
|
|
33
|
+
className: cn('break-words', surface === 'inline' && !readOnly && 'rounded-sm border-transparent bg-transparent px-1 py-1 text-xs shadow-none outline-none hover:bg-accent/40 focus:border-transparent focus:ring-1 focus:ring-inset focus:ring-ring', autoSize ? '[font:inherit]' : 'font-mono', readOnly && READONLY_SURFACE_CLASSES, invalid && 'border-destructive focus:border-destructive focus:ring-destructive/20') }));
|
|
34
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export interface WidgetOption {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
color?: string;
|
|
5
|
+
}
|
|
6
|
+
export type WidgetOptions = ReadonlyArray<string | number | WidgetOption>;
|
|
7
|
+
export type UiHint = {
|
|
8
|
+
type: 'text';
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
multiline?: boolean;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'number';
|
|
13
|
+
min?: number;
|
|
14
|
+
max?: number;
|
|
15
|
+
step?: number;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'select';
|
|
18
|
+
options: string[];
|
|
19
|
+
} | {
|
|
20
|
+
type: 'multi-select';
|
|
21
|
+
options: string[];
|
|
22
|
+
} | {
|
|
23
|
+
type: 'checkbox';
|
|
24
|
+
} | {
|
|
25
|
+
type: 'date-picker';
|
|
26
|
+
} | null;
|
|
27
|
+
export interface InputMetadata {
|
|
28
|
+
type: 'string' | 'float' | 'boolean' | 'array';
|
|
29
|
+
title?: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
required?: boolean;
|
|
32
|
+
ui_hint?: UiHint;
|
|
33
|
+
}
|
|
34
|
+
export interface WidgetProps {
|
|
35
|
+
value: string;
|
|
36
|
+
onChange: (value: string) => void;
|
|
37
|
+
onBlur: () => void;
|
|
38
|
+
ariaLabel?: string;
|
|
39
|
+
ariaDescribedBy?: string;
|
|
40
|
+
invalid?: boolean;
|
|
41
|
+
options?: WidgetOptions;
|
|
42
|
+
emptyOptionLabel?: string;
|
|
43
|
+
minHeight?: number;
|
|
44
|
+
autoSize?: boolean;
|
|
45
|
+
surface?: 'default' | 'inline';
|
|
46
|
+
readOnly?: boolean;
|
|
47
|
+
disabled?: boolean;
|
|
48
|
+
metadata?: InputMetadata;
|
|
49
|
+
uiHint?: UiHint;
|
|
50
|
+
}
|
|
51
|
+
export interface DirectSaveWidgetProps extends WidgetProps {
|
|
52
|
+
onDirectSave: (value: unknown) => void;
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@script-it/json-views-react",
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
|
+
"description": "Extensible React viewer and editor for JSON Views",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./styles.css": "./dist/styles.css",
|
|
15
|
+
"./standalone.css": "./dist/standalone.css"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE",
|
|
21
|
+
"THIRD_PARTY_NOTICES.txt"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "node ../../scripts/clean-dist.mjs && tsc -p tsconfig.json && tailwindcss -i src/styles.css -o dist/styles.css --minify && node ../../scripts/scope-styles.mjs",
|
|
25
|
+
"check": "tsc -p tsconfig.json --noEmit",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"prepack": "node ../../scripts/prepare-package.mjs"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@codemirror/lang-json": "^6.0.2",
|
|
31
|
+
"@codemirror/language": "^6.12.4",
|
|
32
|
+
"@codemirror/state": "^6.7.4",
|
|
33
|
+
"@codemirror/view": "^6.43.11",
|
|
34
|
+
"@lezer/highlight": "^1.2.3",
|
|
35
|
+
"@radix-ui/react-checkbox": "^1.3.3",
|
|
36
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
37
|
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
38
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
39
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
40
|
+
"@radix-ui/react-tooltip": "^1.2.8",
|
|
41
|
+
"@script-it/json-views-core": "0.1.0-beta.1",
|
|
42
|
+
"@tanstack/react-virtual": "3.14.10",
|
|
43
|
+
"class-variance-authority": "^0.7.1",
|
|
44
|
+
"clsx": "^2.1.1",
|
|
45
|
+
"codemirror": "^6.0.2",
|
|
46
|
+
"js-yaml": "^4.1.0",
|
|
47
|
+
"lucide-react": "^0.561.0",
|
|
48
|
+
"tailwind-merge": "^3.3.1"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
52
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@tailwindcss/cli": "^4.1.13",
|
|
56
|
+
"@types/js-yaml": "^4.0.9",
|
|
57
|
+
"@types/react": "^19.1.16",
|
|
58
|
+
"@types/react-dom": "^19.1.9",
|
|
59
|
+
"jsdom": "29.0.2",
|
|
60
|
+
"react": "^19.1.1",
|
|
61
|
+
"react-dom": "^19.1.1",
|
|
62
|
+
"typescript": "^5.9.3",
|
|
63
|
+
"vitest": "3.2.7"
|
|
64
|
+
},
|
|
65
|
+
"repository": {
|
|
66
|
+
"type": "git",
|
|
67
|
+
"url": "git+https://github.com/script-it/json-views.git",
|
|
68
|
+
"directory": "packages/react"
|
|
69
|
+
},
|
|
70
|
+
"homepage": "https://github.com/script-it/json-views#readme",
|
|
71
|
+
"bugs": {
|
|
72
|
+
"url": "https://github.com/script-it/json-views/issues"
|
|
73
|
+
},
|
|
74
|
+
"engines": {
|
|
75
|
+
"node": "^22.13.0 || >=24.0.0"
|
|
76
|
+
},
|
|
77
|
+
"sideEffects": [
|
|
78
|
+
"**/*.css"
|
|
79
|
+
],
|
|
80
|
+
"publishConfig": {
|
|
81
|
+
"access": "public"
|
|
82
|
+
}
|
|
83
|
+
}
|