@jbrowse/plugin-config 5.0.0-beta.8 → 5.0.0-beta.9

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.
@@ -1,9 +1,10 @@
1
1
  /** #slotEditor text field beside a swatch that opens a color picker */
2
- declare const ColorEditor: (props: {
2
+ declare const ColorEditor: ({ slot, }: {
3
3
  slot: {
4
4
  name: string;
5
5
  value: string | undefined;
6
6
  description: string;
7
+ contextVariable?: string[];
7
8
  set: (arg: string) => void;
8
9
  };
9
10
  }) => import("react").JSX.Element;
@@ -1,5 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Suspense, lazy } from 'react';
2
+ import { Suspense, lazy, useState } from 'react';
3
+ import { isCssColor } from '@jbrowse/core/util/colorBits';
4
+ import { isJexl } from '@jbrowse/core/util/jexlStrings';
3
5
  import { makeStyles } from '@jbrowse/core/util/tss-react';
4
6
  import { observer } from 'mobx-react';
5
7
  import ConfigurationTextField from './ConfigurationTextField.js';
@@ -17,18 +19,33 @@ const useStyles = makeStyles()({
17
19
  });
18
20
  // Also drives `maybeColor`, whose value is `undefined` while unset. An empty
19
21
  // string keeps the field controlled and the picker fed, the same way
20
- // NumberEditor renders an unset `maybeNumber` as an empty field. Clearing the
21
- // field writes `''` rather than restoring `undefined` — "unset" is reachable
22
- // through the slot's reset button, which is where every other slot type puts it.
22
+ // NumberEditor renders an unset `maybeNumber` as an empty field. The slot
23
+ // refuses what is not a color, so text that does not parse yet stays a draft
24
+ // in the field and reaches the slot once it does; leaving the field drops an
25
+ // unparsed draft. "Unset" is reachable through the slot's reset button, which
26
+ // is where every other slot type puts it. Only a slot declaring a
27
+ // `contextVariable` takes a `jexl:` callback, which an entry of a colour list
28
+ // never does.
23
29
  /** #slotEditor text field beside a swatch that opens a color picker */
24
- const ColorEditor = observer(function ColorEditor(props) {
25
- const { slot } = props;
30
+ const ColorEditor = observer(function ColorEditor({ slot, }) {
31
+ const admitsJexl = !!slot.contextVariable?.length;
26
32
  const { classes } = useStyles();
33
+ const [draft, setDraft] = useState();
27
34
  const value = slot.value ?? '';
28
- return (_jsxs("div", { className: classes.root, children: [_jsx(ConfigurationTextField, { value: value, label: slot.name, helperText: slot.description, className: classes.field, onChange: event => {
29
- slot.set(event.target.value);
35
+ return (_jsxs("div", { className: classes.root, children: [_jsx(ConfigurationTextField, { value: draft ?? value, label: slot.name, error: draft !== undefined, helperText: draft === undefined ? slot.description : `"${draft}" is not a color`, className: classes.field, onChange: event => {
36
+ const text = event.target.value;
37
+ if (isCssColor(text) || (admitsJexl && isJexl(text))) {
38
+ slot.set(text);
39
+ setDraft(undefined);
40
+ }
41
+ else {
42
+ setDraft(text);
43
+ }
44
+ }, onBlur: () => {
45
+ setDraft(undefined);
30
46
  } }), _jsx(Suspense, { fallback: null, children: _jsx(PopoverPicker, { color: value, onChange: color => {
31
47
  slot.set(color);
48
+ setDraft(undefined);
32
49
  } }) })] }));
33
50
  });
34
51
  export default ColorEditor;
@@ -1,14 +1,17 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
- import { getSlotDefinition, getTypeNamesFromExplicitlyTypedUnion, isConfigurationModel, isConfigurationSchemaType, isConfigurationSlot, makeSlotFacade, readConfObject, } from '@jbrowse/core/configuration';
3
+ import { arraySlotUnion, getSlotDefinition, getTypeNamesFromExplicitlyTypedUnion, isConfigurationModel, isConfigurationSchemaType, isConfigurationSlot, makeSlotFacade, readConfObject, setConf, } from '@jbrowse/core/configuration';
4
4
  import SanitizedHTML from '@jbrowse/core/ui/SanitizedHTML';
5
5
  import { makeStyles } from '@jbrowse/core/util/tss-react';
6
- import { getMembers } from '@jbrowse/mobx-state-tree';
6
+ import { getMembers, getSnapshot } from '@jbrowse/mobx-state-tree';
7
+ import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
8
+ import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
7
9
  import ClearIcon from '@mui/icons-material/Clear';
10
+ import DeleteIcon from '@mui/icons-material/Delete';
8
11
  import ExpandLessIcon from '@mui/icons-material/ExpandLess';
9
12
  import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
10
13
  import SearchIcon from '@mui/icons-material/Search';
11
- import { Accordion, AccordionDetails, AccordionSummary, Button, IconButton, InputAdornment, TextField, Typography, } from '@mui/material';
14
+ import { Accordion, AccordionDetails, AccordionSummary, Button, IconButton, InputAdornment, MenuItem, TextField, Typography, } from '@mui/material';
12
15
  import { observer } from 'mobx-react';
13
16
  import SlotEditor from './SlotEditor.js';
14
17
  import TypeSelector from './TypeSelector.js';
@@ -39,7 +42,15 @@ const useStyles = makeStyles()(theme => ({
39
42
  margin: theme.spacing(1, 0),
40
43
  textTransform: 'none',
41
44
  },
45
+ entryControls: {
46
+ display: 'flex',
47
+ justifyContent: 'flex-end',
48
+ },
42
49
  }));
50
+ // The entries of an array of sub-schemas as snapshots, for a whole-list write.
51
+ function listSnapshot(schema, listName) {
52
+ return [...getSnapshot(schema[listName])];
53
+ }
43
54
  // matches a slot or sub-schema against a lowercased filter string, recursing
44
55
  // into sub-schemas so a nested slot name keeps its ancestors visible
45
56
  function memberMatches(schema, slotName, slotSchema, query) {
@@ -53,7 +64,7 @@ function memberMatches(schema, slotName, slotSchema, query) {
53
64
  return (slotName.toLowerCase().includes(query) ||
54
65
  (Array.isArray(slot)
55
66
  ? slot.some(subslot => schemaMatches(subslot, query))
56
- : schemaMatches(slot, query)));
67
+ : slot !== undefined && schemaMatches(slot, query)));
57
68
  }
58
69
  else {
59
70
  return false;
@@ -77,9 +88,32 @@ function displayDefaultExpanded(slot, expandedDisplayId) {
77
88
  : undefined;
78
89
  return !displayId || !expandedDisplayId || displayId === expandedDisplayId;
79
90
  }
91
+ // A union list entry's own controls: its type, and its place in the list. Each
92
+ // is one whole-list write, so every state it leaves loads again.
93
+ const EntryControls = observer(function EntryControls({ schema, title, slot, entry: { listName, choices, index, count }, }) {
94
+ const { classes } = useStyles();
95
+ const write = (edit) => {
96
+ setConf(schema, listName, edit(listSnapshot(schema, listName)));
97
+ };
98
+ const swap = (at) => {
99
+ write(list => list.toSpliced(at, 2, list[at + 1], list[at]));
100
+ };
101
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: classes.entryControls, children: [_jsx(IconButton, { "aria-label": `move ${title} up`, disabled: index === 0, onClick: () => {
102
+ swap(index - 1);
103
+ }, children: _jsx(ArrowUpwardIcon, { fontSize: "small" }) }), _jsx(IconButton, { "aria-label": `move ${title} down`, disabled: index === count - 1, onClick: () => {
104
+ swap(index);
105
+ }, children: _jsx(ArrowDownwardIcon, { fontSize: "small" }) }), _jsx(IconButton, { "aria-label": `remove ${title}`, onClick: () => {
106
+ write(list => list.toSpliced(index, 1));
107
+ }, children: _jsx(DeleteIcon, { fontSize: "small" }) })] }), _jsx(TypeSelector, { typeNameChoices: choices, slotName: title, slot: slot, onChange: evt => {
108
+ const type = evt.target.value;
109
+ if (type !== slot.type) {
110
+ write(list => list.with(index, { type }));
111
+ }
112
+ } })] }));
113
+ });
80
114
  const Member = observer(function Member(props) {
81
115
  const { classes } = useStyles();
82
- const { slotName, slotSchema, schema, slot = schema[slotName], path = [], filter = '', expandedDisplayId, } = props;
116
+ const { slotName, slotSchema, schema, slot = schema[slotName], path = [], filter = '', expandedDisplayId, entry, } = props;
83
117
  // when the sub-schema's own name matches, drop the filter for its children so
84
118
  // the whole group stays visible; otherwise keep filtering descendants
85
119
  const childFilter = slotName.toLowerCase().includes(filter.toLowerCase())
@@ -91,12 +125,7 @@ const Member = observer(function Member(props) {
91
125
  // keyed on Array.isArray, not `.length` truthiness, so an empty array maps
92
126
  // to nothing instead of being mis-handled as a single schema
93
127
  if (Array.isArray(slot)) {
94
- return slot.map((subslot, slotIndex) => {
95
- const key = subslot.type
96
- ? `${singularSlotName(slotName)} ${subslot.type}`
97
- : `${singularSlotName(slotName)} ${slotIndex + 1}`;
98
- return _jsx(Member, { ...props, slot: subslot, slotName: key }, key);
99
- });
128
+ return _jsx(EntryList, { ...props, entries: slot });
100
129
  }
101
130
  // if this is an explicitly typed schema, make a type-selecting dropdown
102
131
  // that can be used to change its type
@@ -107,13 +136,13 @@ const Member = observer(function Member(props) {
107
136
  // visible, not just present in the collapsed DOM. The key flips the
108
137
  // accordion between filtered/unfiltered mounts so the new
109
138
  // defaultExpanded takes effect (Accordion reads it only on mount).
110
- , { defaultExpanded: filter ? true : displayDefaultExpanded(slot, expandedDisplayId), className: classes.accordion, children: [_jsx(AccordionSummary, { expandIcon: _jsx(ExpandMoreIcon, { className: classes.icon }), children: _jsx(Typography, { children: [...path, slotName].join('➔') }) }), _jsxs(AccordionDetails, { className: classes.expansionPanelDetails, children: [typeNameChoices.length ? (_jsx(TypeSelector, { typeNameChoices: typeNameChoices, slotName: slotName, slot: slot, onChange: evt => {
111
- if (evt.target.value !== slot.type) {
139
+ , { defaultExpanded: filter ? true : displayDefaultExpanded(slot, expandedDisplayId), className: classes.accordion, children: [_jsx(AccordionSummary, { expandIcon: _jsx(ExpandMoreIcon, { className: classes.icon }), children: _jsx(Typography, { children: [...path, slotName].join('➔') }) }), _jsxs(AccordionDetails, { className: classes.expansionPanelDetails, children: [entry && slot ? (_jsx(EntryControls, { schema: schema, title: slotName, slot: slot, entry: entry })) : null, typeNameChoices.length ? (_jsx(TypeSelector, { typeNameChoices: typeNameChoices, slotName: slotName, slot: slot, onChange: evt => {
140
+ if (evt.target.value !== slot?.type) {
112
141
  schema.setSubschema(slotName, {
113
142
  type: evt.target.value,
114
143
  });
115
144
  }
116
- } })) : null, _jsx("div", { className: classes.noOverflow, children: _jsx(Schema, { schema: slot, path: [...path, slotName], filter: childFilter, expandedDisplayId: expandedDisplayId }) })] })] }, filter ? 'filtered' : 'unfiltered'));
145
+ } })) : null, slot ? (_jsx("div", { className: classes.noOverflow, children: _jsx(Schema, { schema: slot, path: [...path, slotName], filter: childFilter, expandedDisplayId: expandedDisplayId }) })) : null] })] }, filter ? 'filtered' : 'unfiltered'));
117
146
  }
118
147
  else if (isConfigurationSlot(schema, slotName)) {
119
148
  return _jsx(SlotEditor, { slot: makeSlotFacade(schema, slotName) }, slotName);
@@ -122,6 +151,30 @@ const Member = observer(function Member(props) {
122
151
  return null;
123
152
  }
124
153
  });
154
+ // An array of sub-schemas, one accordion per entry. A list whose entries are a
155
+ // `ConfigurationSchemaUnion` also offers each entry's type and place, and a new
156
+ // entry of any member type; a pluggable union such as a track's `displays` is
157
+ // not one, since a display is added through the track.
158
+ const EntryList = observer(function EntryList(props) {
159
+ const { classes } = useStyles();
160
+ const { slotName, slotSchema, schema, entries } = props;
161
+ const singular = singularSlotName(slotName);
162
+ const union = arraySlotUnion(slotSchema);
163
+ const choices = union ? Object.keys(union.members) : [];
164
+ return (_jsxs(_Fragment, { children: [entries.map((subslot, index) => {
165
+ const title = `${singular} ${index + 1}`;
166
+ return (_jsx(Member
167
+ // eslint-disable-next-line @eslint-react/no-array-index-key -- a config entry has no identity but its place
168
+ , { ...props, slot: subslot, slotName: union || !subslot.type ? title : `${title} ${subslot.type}`, entry: union
169
+ ? { listName: slotName, choices, index, count: entries.length }
170
+ : undefined }, index));
171
+ }), union ? (_jsx(TextField, { className: classes.filter, select: true, size: "small", label: `Add ${singular}`, value: "", onChange: evt => {
172
+ setConf(schema, slotName, [
173
+ ...listSnapshot(schema, slotName),
174
+ { type: evt.target.value },
175
+ ]);
176
+ }, fullWidth: true, children: choices.map(type => (_jsx(MenuItem, { value: type, children: type }, type))) })) : null] }));
177
+ });
125
178
  const Schema = observer(function Schema({ schema, path = [], filter = '', expandedDisplayId, }) {
126
179
  const { classes } = useStyles();
127
180
  const [showAdvanced, setShowAdvanced] = useState(false);
@@ -0,0 +1,17 @@
1
+ interface ListSlot {
2
+ name: string;
3
+ value: string[];
4
+ description: string;
5
+ set: (arg: string[]) => void;
6
+ }
7
+ /** #slotEditor a text field and color picker per entry, with add and delete */
8
+ declare const ColorArrayEditor: ({ slot, }: {
9
+ slot: ListSlot;
10
+ }) => import("react").JSX.Element;
11
+ /** #slotEditor a dropdown of the `model`'s members per entry, with add and delete */
12
+ declare const StringEnumArrayEditor: ({ slot, }: {
13
+ slot: ListSlot & {
14
+ choices?: string[];
15
+ };
16
+ }) => import("react").JSX.Element;
17
+ export { ColorArrayEditor, StringEnumArrayEditor };
@@ -0,0 +1,35 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import AddIcon from '@mui/icons-material/Add';
3
+ import DeleteIcon from '@mui/icons-material/Delete';
4
+ import { FormHelperText, IconButton, InputLabel, List, ListItem, MenuItem, } from '@mui/material';
5
+ import { observer } from 'mobx-react';
6
+ import ColorEditor from './ColorEditor.js';
7
+ import ConfigurationTextField from './ConfigurationTextField.js';
8
+ // A list slot whose entries each take one control: the list is written whole
9
+ // on every change, and "add" appends an entry the slot already admits, so no
10
+ // write can hold an entry the slot refuses.
11
+ const EntryList = observer(function EntryList({ slot, entry, added, }) {
12
+ const value = [...slot.value];
13
+ const addition = added(value);
14
+ return (_jsxs(_Fragment, { children: [slot.name ? _jsx(InputLabel, { children: slot.name }) : null, _jsxs(List, { disablePadding: true, children: [value.map((v, idx) => (_jsxs(ListItem, { disableGutters: true, children: [entry(v, next => {
15
+ slot.set(value.map((old, i) => (i === idx ? next : old)));
16
+ }), _jsx(IconButton, { "aria-label": "delete entry", onClick: () => {
17
+ slot.set(value.filter((_, i) => i !== idx));
18
+ }, children: _jsx(DeleteIcon, {}) })] }, idx))), _jsx(ListItem, { disableGutters: true, children: _jsx(IconButton, { "data-testid": `entryAdd-${slot.name}`, "aria-label": "add entry", disabled: addition === undefined, onClick: () => {
19
+ if (addition !== undefined) {
20
+ slot.set([...value, addition]);
21
+ }
22
+ }, children: _jsx(AddIcon, {}) }) })] }), _jsx(FormHelperText, { children: slot.description })] }));
23
+ });
24
+ /** #slotEditor a text field and color picker per entry, with add and delete */
25
+ const ColorArrayEditor = observer(function ColorArrayEditor({ slot, }) {
26
+ return (_jsx(EntryList, { slot: slot, added: value => value.at(-1) ?? 'black', entry: (color, set) => (_jsx(ColorEditor, { slot: { name: '', description: '', value: color, set } })) }));
27
+ });
28
+ /** #slotEditor a dropdown of the `model`'s members per entry, with add and delete */
29
+ const StringEnumArrayEditor = observer(function StringEnumArrayEditor({ slot, }) {
30
+ const choices = slot.choices ?? [];
31
+ return (_jsx(EntryList, { slot: slot, added: () => choices[0], entry: (member, set) => (_jsx(ConfigurationTextField, { select: true, value: member, onChange: evt => {
32
+ set(evt.target.value);
33
+ }, children: choices.map(choice => (_jsx(MenuItem, { value: choice, children: choice }, choice))) })) }));
34
+ });
35
+ export { ColorArrayEditor, StringEnumArrayEditor };
@@ -10,6 +10,7 @@ import BooleanEditor from './BooleanEditor.js';
10
10
  import CallbackEditor from './CallbackEditor.js';
11
11
  import ColorEditor from './ColorEditor.js';
12
12
  import ConfigurationTextField from './ConfigurationTextField.js';
13
+ import { ColorArrayEditor, StringEnumArrayEditor } from './EntryListEditor.js';
13
14
  import IntegerEditor from './IntegerEditor.js';
14
15
  import JsonEditor from './JsonEditor.js';
15
16
  import NumberEditor from './NumberEditor.js';
@@ -17,9 +18,12 @@ import NumberMapEditor from './NumberMapEditor.js';
17
18
  import StringArrayEditor from './StringArrayEditor.js';
18
19
  import StringArrayMapEditor from './StringArrayMapEditor.js';
19
20
  import { useSlotEditorStyles } from './useSlotEditorStyles.js';
21
+ // Also drives `maybeString`, whose value is `undefined` while unset: clearing
22
+ // the field leaves the empty string, which is a value, and the reset button
23
+ // returns the slot to unset.
20
24
  /** #slotEditor single-line text field */
21
25
  const StringEditor = observer(function StringEditor({ slot, }) {
22
- return (_jsx(ConfigurationTextField, { label: slot.name, helperText: slot.description, value: slot.value, onChange: evt => {
26
+ return (_jsx(ConfigurationTextField, { label: slot.name, helperText: slot.description, value: slot.value ?? '', onChange: evt => {
23
27
  slot.set(evt.target.value);
24
28
  } }));
25
29
  });
@@ -54,9 +58,13 @@ const FileSelectorWrapper = observer(function FileSelectorWrapper({ slot, }) {
54
58
  // The editors stay fully typed internally; only this lookup is untyped.
55
59
  const valueComponents = {
56
60
  string: StringEditor,
61
+ maybeString: StringEditor,
62
+ featureField: StringEditor,
57
63
  text: TextEditor,
58
64
  fileLocation: FileSelectorWrapper,
59
65
  stringArray: StringArrayEditor,
66
+ colorArray: ColorArrayEditor,
67
+ stringEnumArray: StringEnumArrayEditor,
60
68
  stringArrayMap: StringArrayMapEditor,
61
69
  numberMap: NumberMapEditor,
62
70
  number: NumberEditor,
@@ -77,8 +85,10 @@ const SlotEditor = observer(function SlotEditor({ slot, }) {
77
85
  // editor mode is UI-only state, derived once from whether the stored value is
78
86
  // a jexl callback. Toggling rewrites the value; typing a "jexl:" prefix into a
79
87
  // value field does not auto-swap the editor, since this state only changes on
80
- // the explicit toggle.
81
- const [callbackMode, setCallbackMode] = useState(() => isCallbackValue(slot.value));
88
+ // the explicit toggle. A featureField's `jexl:` expression is a field, typed
89
+ // in its own text field.
90
+ const callback = slot.contextVariable.length > 0;
91
+ const [callbackMode, setCallbackMode] = useState(() => callback && isCallbackValue(slot.value));
82
92
  // bumped on reset to remount the value editor: the buffered editors (number,
83
93
  // json, callback) seed internal state from slot.value only on mount, so an
84
94
  // external set wouldn't otherwise show in the field
@@ -93,9 +103,9 @@ const SlotEditor = observer(function SlotEditor({ slot, }) {
93
103
  const { modified } = slot;
94
104
  return (_jsxs(Paper, { className: classes.paper, children: [_jsx("div", { className: classes.paperContent, children: _jsx(ValueComponent, { slot: slot }, resetNonce) }), modified ? (_jsx("div", { className: classes.resetButton, children: _jsx(Tooltip, { title: "Reset to default", children: _jsx(IconButton, { "aria-label": "reset to default", onClick: () => {
95
105
  slot.set(slot.defaultValue);
96
- setCallbackMode(isCallbackValue(slot.defaultValue));
106
+ setCallbackMode(callback && isCallbackValue(slot.defaultValue));
97
107
  setResetNonce(nonce => nonce + 1);
98
- }, children: _jsx(RestartAltIcon, {}) }) }) })) : null, slot.contextVariable.length ? (_jsx("div", { className: classes.slotModeSwitch, children: _jsx(Tooltip, { title: callbackMode
108
+ }, children: _jsx(RestartAltIcon, {}) }) }) })) : null, callback ? (_jsx("div", { className: classes.slotModeSwitch, children: _jsx(Tooltip, { title: callbackMode
99
109
  ? 'Editing as a callback (Jexl expression). Click to use a fixed value.'
100
110
  : 'Editing as a fixed value. Click to use a callback (Jexl expression).', children: _jsx(IconButton, { color: callbackMode ? 'primary' : 'default', onClick: () => {
101
111
  if (callbackMode) {
@@ -1,7 +1,7 @@
1
1
  import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
2
2
  declare const TypeSelector: ({ typeNameChoices, slot, slotName, onChange, }: {
3
3
  typeNameChoices: string[];
4
- slot: AnyConfigurationModel;
4
+ slot: AnyConfigurationModel | undefined;
5
5
  slotName: string;
6
6
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
7
7
  }) => import("react").JSX.Element;
@@ -4,6 +4,6 @@ import { observer } from 'mobx-react';
4
4
  import { useSlotEditorStyles } from './useSlotEditorStyles.js';
5
5
  const TypeSelector = observer(function TypeSelector({ typeNameChoices, slot, slotName, onChange, }) {
6
6
  const { classes } = useSlotEditorStyles();
7
- return (_jsx(Paper, { className: classes.paper, children: _jsx("div", { className: classes.paperContent, children: _jsx(TextField, { value: slot.type, label: "Type", select: true, variant: "outlined", helperText: `Type of ${slotName} to use`, fullWidth: true, onChange: onChange, children: typeNameChoices.map(str => (_jsx(MenuItem, { value: str, children: str }, str))) }) }) }));
7
+ return (_jsx(Paper, { className: classes.paper, children: _jsx("div", { className: classes.paperContent, children: _jsx(TextField, { value: slot?.type ?? '', label: `Type of ${slotName}`, select: true, variant: "outlined", fullWidth: true, onChange: onChange, children: typeNameChoices.map(str => (_jsx(MenuItem, { value: str, children: str }, str))) }) }) }));
8
8
  });
9
9
  export default TypeSelector;
@@ -16,25 +16,20 @@
16
16
  * ```
17
17
  */
18
18
  declare const configSchema: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
19
- /**
20
- * #slot
21
- * stable identifier used as the adapter cache key; avoids hashing the
22
- * (potentially large) features array. optional — falls back to hash.
23
- */
19
+ type: {
20
+ type: "string";
21
+ } & {
22
+ defaultValue: string;
23
+ };
24
24
  readonly adapterId: {
25
- readonly type: "string";
26
- readonly defaultValue: "";
25
+ type: "string";
26
+ } & {
27
+ defaultValue: string;
27
28
  };
28
- /**
29
- * #slot
30
- * the features themselves, as an array of plain objects. Each needs a
31
- * `uniqueId`, `refName`, `start` and `end` (0-based half-open); anything
32
- * else — `name`, `type`, `score`, `strand`, nested `subfeatures` — is
33
- * carried through onto the feature as-is.
34
- */
35
29
  readonly features: {
36
- readonly type: "frozen";
37
- readonly defaultValue: readonly [];
30
+ type: "frozen";
31
+ } & {
32
+ defaultValue: unknown;
38
33
  };
39
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
34
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>>>;
40
35
  export default configSchema;
@@ -22,25 +22,20 @@
22
22
  * ```
23
23
  */
24
24
  declare const regionsConfigSchema: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
25
- /**
26
- * #slot
27
- * stable identifier used as the adapter cache key; avoids hashing the
28
- * (potentially large) features array. optional — falls back to hash.
29
- */
25
+ type: {
26
+ type: "string";
27
+ } & {
28
+ defaultValue: string;
29
+ };
30
30
  readonly adapterId: {
31
- readonly type: "string";
32
- readonly defaultValue: "";
31
+ type: "string";
32
+ } & {
33
+ defaultValue: string;
33
34
  };
34
- /**
35
- * #slot
36
- * one entry per reference sequence, each with a `uniqueId`, `refName`,
37
- * `start: 0` and `end` set to that sequence's length. This is what defines
38
- * the assembly's reference names and sizes; no bases are supplied, so
39
- * base-level views are empty.
40
- */
41
35
  readonly features: {
42
- readonly type: "frozen";
43
- readonly defaultValue: readonly [];
36
+ type: "frozen";
37
+ } & {
38
+ defaultValue: unknown;
44
39
  };
45
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
40
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>>>;
46
41
  export default regionsConfigSchema;
@@ -21,25 +21,20 @@
21
21
  * ```
22
22
  */
23
23
  declare const sequenceConfigSchema: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
24
- /**
25
- * #slot
26
- * stable identifier used as the adapter cache key; avoids hashing the
27
- * (potentially large) features array. optional — falls back to hash.
28
- */
24
+ type: {
25
+ type: "string";
26
+ } & {
27
+ defaultValue: string;
28
+ };
29
29
  readonly adapterId: {
30
- readonly type: "string";
31
- readonly defaultValue: "";
30
+ type: "string";
31
+ } & {
32
+ defaultValue: string;
32
33
  };
33
- /**
34
- * #slot
35
- * one entry per reference sequence, each with a `uniqueId`, `refName`,
36
- * `start`, `end`, and a `seq` string holding the bases for that span. The
37
- * bases live in the config, so this is for small sequences — a plasmid, a
38
- * test contig — not a genome.
39
- */
40
34
  readonly features: {
41
- readonly type: "frozen";
42
- readonly defaultValue: readonly [];
35
+ type: "frozen";
36
+ } & {
37
+ defaultValue: unknown;
43
38
  };
44
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
39
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>>>;
45
40
  export default sequenceConfigSchema;
@@ -57,27 +57,21 @@ export declare const normalizeSnapshot: typeof normalizeUriSnapshot;
57
57
  * ```
58
58
  */
59
59
  declare const NcbiSequenceReportAliasAdapterConfigSchema: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
60
- /**
61
- * #slot
62
- * location of the `sequence_report.tsv` NCBI publishes with an assembly. It
63
- * carries the RefSeq, GenBank and UCSC-style name of every sequence, so one
64
- * file aliases them all without hand-writing a chromAlias table.
65
- */
60
+ type: {
61
+ type: "string";
62
+ } & {
63
+ defaultValue: string;
64
+ };
66
65
  readonly location: {
67
- readonly type: "fileLocation";
68
- readonly defaultValue: {
69
- readonly uri: "/path/to/my/sequence_report.tsv";
70
- readonly locationType: "UriLocation";
71
- };
66
+ type: "fileLocation";
67
+ } & {
68
+ defaultValue: unknown;
72
69
  };
73
- /**
74
- * #slot
75
- */
76
70
  readonly useNameOverride: {
77
- readonly type: "boolean";
78
- readonly defaultValue: true;
79
- readonly description: "forces usage of the UCSC names over the NCBI style names from a FASTA";
71
+ type: "boolean";
72
+ } & {
73
+ defaultValue: boolean;
80
74
  };
81
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
75
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>>>;
82
76
  export type NcbiSequenceReportAliasAdapterConfig = Instance<typeof NcbiSequenceReportAliasAdapterConfigSchema>;
83
77
  export default NcbiSequenceReportAliasAdapterConfigSchema;
@@ -55,40 +55,26 @@ export declare const normalizeSnapshot: typeof normalizeUriSnapshot;
55
55
  * ```
56
56
  */
57
57
  declare const RefNameAliasAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
58
- /**
59
- * #slot
60
- * location of the alias table: a UCSC `chromAlias.txt`, or any
61
- * tab-separated file whose rows each list the alternate names of one
62
- * reference sequence (`chr1<TAB>1<TAB>NC_000001.11`). It is what lets a
63
- * `1`-named file load against a `chr1`-named assembly.
64
- */
58
+ type: {
59
+ type: "string";
60
+ } & {
61
+ defaultValue: string;
62
+ };
65
63
  readonly location: {
66
- readonly type: "fileLocation";
67
- readonly defaultValue: {
68
- readonly uri: "/path/to/my/aliases.txt";
69
- readonly locationType: "UriLocation";
70
- };
64
+ type: "fileLocation";
65
+ } & {
66
+ defaultValue: unknown;
71
67
  };
72
- /**
73
- * #slot
74
- * by default, the "ref names that match the fasta" are assumed to be in the
75
- * first column (0), change this variable if needed
76
- */
77
68
  readonly refNameColumn: {
78
- readonly type: "number";
79
- readonly defaultValue: 0;
80
- readonly advanced: true;
69
+ type: "number";
70
+ } & {
71
+ defaultValue: number;
81
72
  };
82
- /**
83
- * #slot
84
- * refNameColumnHeaderName
85
- */
86
73
  readonly refNameColumnHeaderName: {
87
- readonly type: "string";
88
- readonly description: "alternative to refNameColumn, instead looks at header (starts with # and finds column name)";
89
- readonly defaultValue: "";
90
- readonly advanced: true;
74
+ type: "string";
75
+ } & {
76
+ defaultValue: string;
91
77
  };
92
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
78
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>>>;
93
79
  export type RefNameAliasAdapterConfig = Instance<typeof RefNameAliasAdapter>;
94
80
  export default RefNameAliasAdapter;
@@ -59,7 +59,7 @@ const RefNameAliasAdapter = ConfigurationSchema('RefNameAliasAdapter', {
59
59
  * #slot
60
60
  * location of the alias table: a UCSC `chromAlias.txt`, or any
61
61
  * tab-separated file whose rows each list the alternate names of one
62
- * reference sequence (`chr1<TAB>1<TAB>NC_000001.11`). It is what lets a
62
+ * reference sequence (`chr1<TAB>1<TAB>NC_000001.11`). The table lets a
63
63
  * `1`-named file load against a `chr1`-named assembly.
64
64
  */
65
65
  location: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-config",
3
- "version": "5.0.0-beta.8",
3
+ "version": "5.0.0-beta.9",
4
4
  "type": "module",
5
5
  "description": "JBrowse 2 config utilities",
6
6
  "keywords": [
@@ -21,13 +21,13 @@
21
21
  "esm"
22
22
  ],
23
23
  "dependencies": {
24
- "@jbrowse/mobx-state-tree": "^6.5.1",
24
+ "@jbrowse/mobx-state-tree": "^6.5.2",
25
25
  "@mui/icons-material": "^9.4.0",
26
26
  "@mui/material": "^9.4.0",
27
27
  "mobx": "^7.0.3",
28
28
  "mobx-react": "^10.0.2",
29
29
  "rxjs": "^7.8.2",
30
- "@jbrowse/core": "^5.0.0-beta.8"
30
+ "@jbrowse/core": "^5.0.0-beta.9"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "react": ">=19.0.0",