mirror of
https://github.com/qlik-oss/nebula.js.git
synced 2025-12-19 17:58:43 -05:00
Tsm/field api (#549)
* feat: add field api and inline listbox * feat: add autosizer * chore: add specs for fieldSelections * feat: support horizontal, set as experimental * fix: close actions correctly * chore: correct docs, set as async
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,6 +15,7 @@ temp/
|
|||||||
test/**/__artifacts__/regression
|
test/**/__artifacts__/regression
|
||||||
test/**/__artifacts__/diff
|
test/**/__artifacts__/diff
|
||||||
apis/*/core/**/*.js
|
apis/*/core/**/*.js
|
||||||
|
apis/*/core/**/*.js.map
|
||||||
apis/locale/all.json
|
apis/locale/all.json
|
||||||
|
|
||||||
Search/
|
Search/
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"react-test-renderer": "17.0.1",
|
"react-test-renderer": "17.0.1",
|
||||||
"react-window": "1.8.6",
|
"react-window": "1.8.6",
|
||||||
"react-window-infinite-loader": "1.0.5",
|
"react-window-infinite-loader": "1.0.5",
|
||||||
|
"react-virtualized-auto-sizer": "^1.0.2",
|
||||||
"semver": "6.3.0"
|
"semver": "6.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ import InfiniteLoader from 'react-window-infinite-loader';
|
|||||||
import useLayout from '../../hooks/useLayout';
|
import useLayout from '../../hooks/useLayout';
|
||||||
|
|
||||||
import Row from './ListBoxRow';
|
import Row from './ListBoxRow';
|
||||||
|
import Column from './ListBoxColumn';
|
||||||
|
|
||||||
export default function ListBox({ model, selections, direction }) {
|
export default function ListBox({ model, selections, direction, height, width, listLayout = 'vertical' }) {
|
||||||
const [layout] = useLayout(model);
|
const [layout] = useLayout(model);
|
||||||
const [pages, setPages] = useState(null);
|
const [pages, setPages] = useState(null);
|
||||||
const loaderRef = useRef(null);
|
const loaderRef = useRef(null);
|
||||||
@@ -117,9 +118,10 @@ export default function ListBox({ model, selections, direction }) {
|
|||||||
if (!layout) {
|
if (!layout) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const isVertical = listLayout !== 'horizontal';
|
||||||
const count = layout.qListObject.qSize.qcy;
|
const count = layout.qListObject.qSize.qcy;
|
||||||
const ITEM_HEIGHT = 33;
|
const ITEM_SIZE = isVertical ? 33 : 200;
|
||||||
|
const listHeight = height || 8 * ITEM_SIZE;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InfiniteLoader
|
<InfiniteLoader
|
||||||
@@ -137,14 +139,16 @@ export default function ListBox({ model, selections, direction }) {
|
|||||||
direction={direction}
|
direction={direction}
|
||||||
useIsScrolling
|
useIsScrolling
|
||||||
style={{}}
|
style={{}}
|
||||||
height={8 * ITEM_HEIGHT}
|
height={listHeight}
|
||||||
|
width={width}
|
||||||
itemCount={count}
|
itemCount={count}
|
||||||
|
layout={listLayout}
|
||||||
itemData={{ onClick, pages }}
|
itemData={{ onClick, pages }}
|
||||||
itemSize={ITEM_HEIGHT}
|
itemSize={ITEM_SIZE}
|
||||||
onItemsRendered={onItemsRendered}
|
onItemsRendered={onItemsRendered}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
{Row}
|
{isVertical ? Row : Column}
|
||||||
</FixedSizeList>
|
</FixedSizeList>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
|||||||
140
apis/nucleus/src/components/listbox/ListBoxColumn.jsx
Normal file
140
apis/nucleus/src/components/listbox/ListBoxColumn.jsx
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { Grid, Typography } from '@material-ui/core';
|
||||||
|
|
||||||
|
import { makeStyles } from '@nebula.js/ui/theme';
|
||||||
|
|
||||||
|
import Lock from '@nebula.js/ui/icons/lock';
|
||||||
|
import Tick from '@nebula.js/ui/icons/tick';
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
column: {
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
borderRight: `1px solid ${theme.palette.divider}`,
|
||||||
|
'&:focus': {
|
||||||
|
boxShadow: `inset 0 0 0 2px ${theme.palette.custom.focusOutline}`,
|
||||||
|
outline: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cell: {
|
||||||
|
padding: '8px',
|
||||||
|
'& span': {
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
fontSize: '12px',
|
||||||
|
lineHeight: '16px',
|
||||||
|
},
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
padding: theme.spacing(1),
|
||||||
|
},
|
||||||
|
S: {
|
||||||
|
background: theme.palette.selected.main,
|
||||||
|
color: theme.palette.selected.mainContrastText,
|
||||||
|
'&:focus': {
|
||||||
|
boxShadow: `inset 0 0 0 2px rgba(0, 0, 0, 0.3)`,
|
||||||
|
outline: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
A: {
|
||||||
|
background: theme.palette.selected.alternative,
|
||||||
|
color: theme.palette.selected.alternativeContrastText,
|
||||||
|
},
|
||||||
|
X: {
|
||||||
|
background: theme.palette.selected.excluded,
|
||||||
|
color: theme.palette.selected.excludedContrastText,
|
||||||
|
},
|
||||||
|
highlighted: {
|
||||||
|
backgroundColor: '#FFC72A',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function Column({ index, style, data }) {
|
||||||
|
const classes = useStyles();
|
||||||
|
const classArr = [classes.column];
|
||||||
|
|
||||||
|
let label = '';
|
||||||
|
const { onClick, pages } = data;
|
||||||
|
let cell;
|
||||||
|
if (pages) {
|
||||||
|
const page = pages.filter((p) => p.qArea.qTop <= index && index < p.qArea.qTop + p.qArea.qHeight)[0];
|
||||||
|
if (page) {
|
||||||
|
const area = page.qArea;
|
||||||
|
if (index >= area.qTop && index < area.qTop + area.qHeight) {
|
||||||
|
[cell] = page.qMatrix[index - area.qTop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let locked = false;
|
||||||
|
let selected = false;
|
||||||
|
if (cell) {
|
||||||
|
label = cell.qText;
|
||||||
|
locked = cell.qState === 'L' || cell.qState === 'XL';
|
||||||
|
selected = cell.qState === 'S' || cell.qState === 'XS';
|
||||||
|
if (cell.qState === 'S' || cell.qState === 'L') {
|
||||||
|
classArr.push(classes.S);
|
||||||
|
} else if (cell.qState === 'A') {
|
||||||
|
classArr.push(classes.A);
|
||||||
|
} else if (cell.qState === 'X' || cell.qState === 'XS' || cell.qState === 'XL') {
|
||||||
|
classArr.push(classes.X);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle search highlights
|
||||||
|
const ranges =
|
||||||
|
(cell && cell.qHighlightRanges && cell.qHighlightRanges.qRanges.sort((a, b) => a.qCharPos - b.qCharPos)) || [];
|
||||||
|
|
||||||
|
const labels = ranges.reduce((acc, curr, ix) => {
|
||||||
|
// First non highlighted segment
|
||||||
|
if (curr.qCharPos > 0 && ix === 0) {
|
||||||
|
acc.push([label.slice(0, curr.qCharPos)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Previous non highlighted segment
|
||||||
|
const prev = ranges[ix - 1];
|
||||||
|
if (prev) {
|
||||||
|
acc.push([label.slice(prev.qCharPos + prev.qCharPos + 1, curr.qCharPos)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Highlighted segment
|
||||||
|
acc.push([label.slice(curr.qCharPos, curr.qCharPos + curr.qCharCount), classes.highlighted]);
|
||||||
|
|
||||||
|
// Last non highlighted segment
|
||||||
|
if (ix === ranges.length - 1 && curr.qCharPos + curr.qCharCount < label.length) {
|
||||||
|
acc.push([label.slice(curr.qCharPos + curr.qCharCount)]);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={0}
|
||||||
|
className={classArr.join(' ').trim()}
|
||||||
|
style={style}
|
||||||
|
onClick={onClick}
|
||||||
|
alignItems="center"
|
||||||
|
role="row"
|
||||||
|
tabIndex={0}
|
||||||
|
data-n={cell && cell.qElemNumber}
|
||||||
|
>
|
||||||
|
<Grid item style={{ minWidth: 0, flexGrow: 1 }} className={classes.cell} title={`${label}`}>
|
||||||
|
{ranges.length === 0 ? (
|
||||||
|
<Typography component="span" noWrap color="inherit">{`${label}`}</Typography>
|
||||||
|
) : (
|
||||||
|
labels.map(([l, highlighted], ix) => (
|
||||||
|
// eslint-disable-next-line react/no-array-index-key
|
||||||
|
<Typography component="span" key={ix} className={highlighted} noWrap>
|
||||||
|
{l}
|
||||||
|
</Typography>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item className={classes.icon}>
|
||||||
|
{locked && <Lock size="small" />}
|
||||||
|
{selected && <Tick size="small" />}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
192
apis/nucleus/src/components/listbox/ListBoxInline.jsx
Normal file
192
apis/nucleus/src/components/listbox/ListBoxInline.jsx
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
import React, { useContext, useCallback, useRef, useEffect, useState } from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||||
|
|
||||||
|
import Lock from '@nebula.js/ui/icons/lock';
|
||||||
|
import Unlock from '@nebula.js/ui/icons/unlock';
|
||||||
|
|
||||||
|
import { IconButton, Grid, Typography } from '@material-ui/core';
|
||||||
|
|
||||||
|
import { useTheme } from '@nebula.js/ui/theme';
|
||||||
|
import useSessionModel from '../../hooks/useSessionModel';
|
||||||
|
import useLayout from '../../hooks/useLayout';
|
||||||
|
|
||||||
|
import ListBox from './ListBox';
|
||||||
|
import createListboxSelectionToolbar from './listbox-selection-toolbar';
|
||||||
|
|
||||||
|
import ActionsToolbar from '../ActionsToolbar';
|
||||||
|
|
||||||
|
import InstanceContext from '../../contexts/InstanceContext';
|
||||||
|
|
||||||
|
import ListBoxSearch from './ListBoxSearch';
|
||||||
|
import useObjectSelections from '../../hooks/useObjectSelections';
|
||||||
|
|
||||||
|
export default function ListBoxPortal({ app, fieldName, stateName, element, options }) {
|
||||||
|
return ReactDOM.createPortal(
|
||||||
|
<ListBoxInline app={app} fieldName={fieldName} stateName={stateName} options={options} />,
|
||||||
|
element
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ListBoxInline({ app, fieldName, stateName = '$', options = {} }) {
|
||||||
|
const theme = useTheme();
|
||||||
|
const { title, direction, listLayout, search = true } = options;
|
||||||
|
const [model] = useSessionModel(
|
||||||
|
{
|
||||||
|
qInfo: {
|
||||||
|
qType: 'njsListbox',
|
||||||
|
},
|
||||||
|
qListObjectDef: {
|
||||||
|
qStateName: stateName,
|
||||||
|
qShowAlternatives: true,
|
||||||
|
qInitialDataFetch: [
|
||||||
|
{
|
||||||
|
qTop: 0,
|
||||||
|
qLeft: 0,
|
||||||
|
qWidth: 0,
|
||||||
|
qHeight: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
qDef: {
|
||||||
|
qSortCriterias: [
|
||||||
|
{
|
||||||
|
qSortByState: 1,
|
||||||
|
qSortByAscii: 1,
|
||||||
|
qSortByNumeric: 1,
|
||||||
|
qSortByLoadOrder: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
qFieldDefs: [fieldName],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
app,
|
||||||
|
fieldName,
|
||||||
|
title,
|
||||||
|
stateName
|
||||||
|
);
|
||||||
|
|
||||||
|
const lock = useCallback(() => {
|
||||||
|
model.lock('/qListObjectDef');
|
||||||
|
}, [model]);
|
||||||
|
|
||||||
|
const unlock = useCallback(() => {
|
||||||
|
model.unlock('/qListObjectDef');
|
||||||
|
}, [model]);
|
||||||
|
|
||||||
|
const { translator } = useContext(InstanceContext);
|
||||||
|
const moreAlignTo = useRef();
|
||||||
|
const [selections] = useObjectSelections(app, model);
|
||||||
|
const [layout] = useLayout(model);
|
||||||
|
const [showToolbar, setShowToolbar] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selections) {
|
||||||
|
if (!selections.isModal(model)) {
|
||||||
|
selections.goModal('/qListObjectDef');
|
||||||
|
selections.on('deactivated', () => {
|
||||||
|
setShowToolbar(false);
|
||||||
|
});
|
||||||
|
selections.on('activated', () => {
|
||||||
|
setShowToolbar(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selections]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selections) {
|
||||||
|
setShowToolbar(selections.isActive());
|
||||||
|
}
|
||||||
|
}, [selections]);
|
||||||
|
|
||||||
|
if (!model || !layout || !translator) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isLocked = layout.qListObject.qDimensionInfo.qLocked === true;
|
||||||
|
|
||||||
|
const listboxSelectionToolbarItems = createListboxSelectionToolbar({
|
||||||
|
layout,
|
||||||
|
model,
|
||||||
|
translator,
|
||||||
|
});
|
||||||
|
|
||||||
|
const counts = layout.qListObject.qDimensionInfo.qStateCounts;
|
||||||
|
|
||||||
|
const hasSelections = counts.qSelected + counts.qSelectedExcluded + counts.qLocked + counts.qLockedExcluded > 0;
|
||||||
|
|
||||||
|
const showTitle = true;
|
||||||
|
|
||||||
|
const minHeight = 49 + (search ? 40 : 0) + 49;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid container direction="column" spacing={0} style={{ height: '100%', minHeight: `${minHeight}px` }}>
|
||||||
|
<Grid item container style={{ padding: theme.spacing(1), borderBottom: `1px solid ${theme.palette.divider}` }}>
|
||||||
|
<Grid item>
|
||||||
|
{isLocked ? (
|
||||||
|
<IconButton onClick={unlock} disabled={!isLocked}>
|
||||||
|
<Lock />
|
||||||
|
</IconButton>
|
||||||
|
) : (
|
||||||
|
<IconButton onClick={lock} disabled={!hasSelections}>
|
||||||
|
<Unlock />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
{showTitle && (
|
||||||
|
<Typography variant="h6" noWrap>
|
||||||
|
{layout.title || fieldName}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs />
|
||||||
|
<Grid item>
|
||||||
|
<ActionsToolbar
|
||||||
|
more={{
|
||||||
|
enabled: !isLocked,
|
||||||
|
actions: listboxSelectionToolbarItems,
|
||||||
|
alignTo: moreAlignTo,
|
||||||
|
popoverProps: {
|
||||||
|
elevation: 0,
|
||||||
|
},
|
||||||
|
popoverPaperStyle: {
|
||||||
|
boxShadow: '0 12px 8px -8px rgba(0, 0, 0, 0.2)',
|
||||||
|
minWidth: '250px',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
selections={{
|
||||||
|
show: showToolbar,
|
||||||
|
api: selections,
|
||||||
|
onConfirm: () => {},
|
||||||
|
onCancel: () => {},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
{search ? (
|
||||||
|
<Grid item>
|
||||||
|
<ListBoxSearch model={model} />
|
||||||
|
</Grid>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
<Grid item xs>
|
||||||
|
<div ref={moreAlignTo} />
|
||||||
|
<AutoSizer>
|
||||||
|
{({ height, width }) => (
|
||||||
|
<ListBox
|
||||||
|
model={model}
|
||||||
|
selections={selections}
|
||||||
|
direction={direction}
|
||||||
|
listLayout={listLayout}
|
||||||
|
height={height}
|
||||||
|
width={width}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</AutoSizer>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -118,7 +118,7 @@ export default function Row({ index, style, data }) {
|
|||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
data-n={cell && cell.qElemNumber}
|
data-n={cell && cell.qElemNumber}
|
||||||
>
|
>
|
||||||
<Grid item style={{ minWidth: 0, flexGrow: 1 }} className={classes.cell}>
|
<Grid item style={{ minWidth: 0, flexGrow: 1 }} className={classes.cell} title={`${label}`}>
|
||||||
{ranges.length === 0 ? (
|
{ranges.length === 0 ? (
|
||||||
<Typography component="span" noWrap color="inherit">{`${label}`}</Typography>
|
<Typography component="span" noWrap color="inherit">{`${label}`}</Typography>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ export default function OneField({
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
api.clearField(selection.qField, field.states[stateIx]);
|
api.clearField(selection.qField, field.states[stateIx]);
|
||||||
}}
|
}}
|
||||||
style={{ zIndex: 1 }}
|
|
||||||
>
|
>
|
||||||
<Remove />
|
<Remove />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import appThemeFn from './app-theme';
|
|||||||
|
|
||||||
import bootNebulaApp from './components/NebulaApp';
|
import bootNebulaApp from './components/NebulaApp';
|
||||||
import AppSelectionsPortal from './components/selections/AppSelections';
|
import AppSelectionsPortal from './components/selections/AppSelections';
|
||||||
|
import ListBoxPortal from './components/listbox/ListBoxInline';
|
||||||
|
|
||||||
import create from './object/create-session-object';
|
import create from './object/create-session-object';
|
||||||
import get from './object/get-object';
|
import get from './object/get-object';
|
||||||
@@ -309,6 +310,66 @@ function nuked(configuration = {}) {
|
|||||||
}
|
}
|
||||||
return selectionsApi;
|
return selectionsApi;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Gets the instance of the specified field
|
||||||
|
* @param {string} fieldName
|
||||||
|
* @returns {Promise<FieldSelections>}
|
||||||
|
* @experimental
|
||||||
|
* @example
|
||||||
|
* const field = await n.field("MyField");
|
||||||
|
* field.mount(element, { title: "Hello Field"});
|
||||||
|
*/
|
||||||
|
field: async (fieldName) => {
|
||||||
|
/**
|
||||||
|
* @class
|
||||||
|
* @hideconstructor
|
||||||
|
* @alias FieldSelections
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
const fieldSels = {
|
||||||
|
fieldName,
|
||||||
|
/**
|
||||||
|
* Mounts the field as a listbox into the provided HTMLElement.
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
* @param {object=} options Settings for the embedded listbox
|
||||||
|
* @param {string=} options.title Custom title, defaults to fieldname
|
||||||
|
* @param {string=} [options.direction=ltr] Direction setting ltr|rtl.
|
||||||
|
* @param {string=} [options.listLayout=vertical] Layout direction vertical|horizontal
|
||||||
|
* @param {boolean=} [options.search=true] To show the search bar
|
||||||
|
* @experimental
|
||||||
|
* @example
|
||||||
|
* field.mount(element);
|
||||||
|
*/
|
||||||
|
mount(element, options = {}) {
|
||||||
|
if (!element) {
|
||||||
|
throw new Error(`Element for ${fieldName} not provided`);
|
||||||
|
}
|
||||||
|
if (this._instance) {
|
||||||
|
throw new Error(`Field ${fieldName} already mounted`);
|
||||||
|
}
|
||||||
|
this._instance = ListBoxPortal({
|
||||||
|
element,
|
||||||
|
app,
|
||||||
|
fieldName,
|
||||||
|
options,
|
||||||
|
});
|
||||||
|
root.add(this._instance);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Unmounts the field listbox from the DOM.
|
||||||
|
* @experimental
|
||||||
|
* @example
|
||||||
|
* field.unmount();
|
||||||
|
*/
|
||||||
|
unmount() {
|
||||||
|
if (this._instance) {
|
||||||
|
root.remove(this._instance);
|
||||||
|
this._instance = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return fieldSels;
|
||||||
|
},
|
||||||
__DO_NOT_USE__: {
|
__DO_NOT_USE__: {
|
||||||
types,
|
types,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"info": {
|
"info": {
|
||||||
"name": "@nebula.js/stardust",
|
"name": "@nebula.js/stardust",
|
||||||
"description": "Product and framework agnostic integration API for Qlik's Associative Engine",
|
"description": "Product and framework agnostic integration API for Qlik's Associative Engine",
|
||||||
"version": "1.0.2-alpha.0",
|
"version": "1.0.2-alpha.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"stability": "stable"
|
"stability": "stable"
|
||||||
},
|
},
|
||||||
@@ -649,6 +649,26 @@
|
|||||||
"// limit constraints\nn.context({ constraints: { active: true } });"
|
"// limit constraints\nn.context({ constraints: { active: true } });"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"field": {
|
||||||
|
"description": "Gets the instance of the specified field",
|
||||||
|
"stability": "experimental",
|
||||||
|
"kind": "function",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"name": "fieldName",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"returns": {
|
||||||
|
"type": "Promise",
|
||||||
|
"generics": [
|
||||||
|
{
|
||||||
|
"type": "#/definitions/FieldSelections"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"examples": ["const field = await n.field(\"MyField\");\nfield.mount(element, { title: \"Hello Field\"});"]
|
||||||
|
},
|
||||||
"render": {
|
"render": {
|
||||||
"description": "Renders a visualization into an HTMLElement.",
|
"description": "Renders a visualization into an HTMLElement.",
|
||||||
"kind": "function",
|
"kind": "function",
|
||||||
@@ -716,6 +736,67 @@
|
|||||||
],
|
],
|
||||||
"type": "any"
|
"type": "any"
|
||||||
},
|
},
|
||||||
|
"FieldSelections": {
|
||||||
|
"stability": "experimental",
|
||||||
|
"kind": "class",
|
||||||
|
"constructor": {
|
||||||
|
"kind": "function",
|
||||||
|
"params": []
|
||||||
|
},
|
||||||
|
"entries": {},
|
||||||
|
"staticEntries": {
|
||||||
|
"mount": {
|
||||||
|
"description": "Mounts the field as a listbox into the provided HTMLElement.",
|
||||||
|
"stability": "experimental",
|
||||||
|
"kind": "function",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"name": "element",
|
||||||
|
"type": "HTMLElement"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "options",
|
||||||
|
"description": "Settings for the embedded listbox",
|
||||||
|
"optional": true,
|
||||||
|
"kind": "object",
|
||||||
|
"entries": {
|
||||||
|
"title": {
|
||||||
|
"description": "Custom title, defaults to fieldname",
|
||||||
|
"optional": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"direction": {
|
||||||
|
"description": "Direction setting ltr|rtl.",
|
||||||
|
"optional": true,
|
||||||
|
"defaultValue": "ltr",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"listLayout": {
|
||||||
|
"description": "Layout direction vertical|horizontal",
|
||||||
|
"optional": true,
|
||||||
|
"defaultValue": "vertical",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"description": "To show the search bar",
|
||||||
|
"optional": true,
|
||||||
|
"defaultValue": true,
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"examples": ["field.mount(element);"]
|
||||||
|
},
|
||||||
|
"unmount": {
|
||||||
|
"description": "Unmounts the field listbox from the DOM.",
|
||||||
|
"stability": "experimental",
|
||||||
|
"kind": "function",
|
||||||
|
"params": [],
|
||||||
|
"examples": ["field.unmount();"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"FieldTarget": {
|
"FieldTarget": {
|
||||||
"kind": "interface",
|
"kind": "interface",
|
||||||
"entries": {
|
"entries": {
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
"react-test-renderer": "17.0.1",
|
"react-test-renderer": "17.0.1",
|
||||||
"react-window": "1.8.6",
|
"react-window": "1.8.6",
|
||||||
"react-window-infinite-loader": "1.0.5",
|
"react-window-infinite-loader": "1.0.5",
|
||||||
|
"react-virtualized-auto-sizer": "^1.0.2",
|
||||||
"regenerator-runtime": "0.13.7",
|
"regenerator-runtime": "0.13.7",
|
||||||
"semver": "6.3.0"
|
"semver": "6.3.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ const config = ({ format = 'umd', debug = false, file, targetPkg }) => {
|
|||||||
format,
|
format,
|
||||||
exports: ['test-utils', 'stardust'].indexOf(targetName) !== -1 ? 'named' : 'default',
|
exports: ['test-utils', 'stardust'].indexOf(targetName) !== -1 ? 'named' : 'default',
|
||||||
name: umdName,
|
name: umdName,
|
||||||
sourcemap: false,
|
sourcemap: true,
|
||||||
banner,
|
banner,
|
||||||
globals,
|
globals,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15685,6 +15685,11 @@ react-transition-group@^4.4.0:
|
|||||||
loose-envify "^1.4.0"
|
loose-envify "^1.4.0"
|
||||||
prop-types "^15.6.2"
|
prop-types "^15.6.2"
|
||||||
|
|
||||||
|
react-virtualized-auto-sizer@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz#a61dd4f756458bbf63bd895a92379f9b70f803bd"
|
||||||
|
integrity sha512-MYXhTY1BZpdJFjUovvYHVBmkq79szK/k7V3MO+36gJkWGkrXKtyr4vCPtpphaTLRAdDNoYEYFZWE8LjN+PIHNg==
|
||||||
|
|
||||||
react-window-infinite-loader@1.0.5:
|
react-window-infinite-loader@1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/react-window-infinite-loader/-/react-window-infinite-loader-1.0.5.tgz#6fe094d538a88978c2c9b623052bc50cb28c2abc"
|
resolved "https://registry.yarnpkg.com/react-window-infinite-loader/-/react-window-infinite-loader-1.0.5.tgz#6fe094d538a88978c2c9b623052bc50cb28c2abc"
|
||||||
|
|||||||
Reference in New Issue
Block a user