diff options
| author | bobzel <zzzman@gmail.com> | 2025-03-24 16:29:32 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2025-03-24 16:29:32 -0400 |
| commit | 858f5d2f1621695a703b0e3f8297521c3ebe692d (patch) | |
| tree | 3180f91ee18bf8accef98cbbb6db6688666e8340 /src/client/views/collections/collectionSchema | |
| parent | 9c5d14fdd562dc1bcc8aa0f73ce7ad189c9fbf23 (diff) | |
| parent | b6cf21b5a52184f89909898d292a79c57c043d7e (diff) | |
Merge branch 'fieldSyntaxUpdate' into aarav_edit
Diffstat (limited to 'src/client/views/collections/collectionSchema')
5 files changed, 87 insertions, 58 deletions
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 0bf78f57c..53c0823ea 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -224,6 +224,7 @@ display: none; } +.schema-table-cell-selected, .schema-table-cell, .row-menu { border: 1px solid global.$medium-gray; @@ -232,6 +233,14 @@ display: inline-flex; padding: 0; align-items: center; + input[type='text'] { + border: unset; + } +} +.schema-table-cell-selected { + input[type='text'] { + background: lightgray; + } } .schemaRTFCell { @@ -310,4 +319,7 @@ .schemaField-editing { outline: none; height: 100%; + cursor: text; + outline: none; + overflow: auto; } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 8e9e8e1cc..05670562e 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -252,7 +252,8 @@ export class CollectionSchemaView extends CollectionSubView() { @action onKeyDown = (e: KeyboardEvent) => { if (this._selectedDocs.length > 0) { - switch (e.key) { + switch (e.key + (e.shiftKey ? 'Shift' : '')) { + case 'Enter': case 'ArrowDown': { const lastDoc = this._selectedDocs.lastElement(); @@ -272,6 +273,7 @@ export class CollectionSchemaView extends CollectionSubView() { e.preventDefault(); } break; + case 'EnterShift': case 'ArrowUp': { const firstDoc = this._selectedDocs.lastElement(); @@ -291,6 +293,7 @@ export class CollectionSchemaView extends CollectionSubView() { e.preventDefault(); } break; + case 'Tab': case 'ArrowRight': if (this._selectedCells) { this._selectedCol = Math.min(this._colEles.length - 1, this._selectedCol + 1); @@ -298,6 +301,7 @@ export class CollectionSchemaView extends CollectionSubView() { this.selectCell(this._selectedDocs[0], 0, false, false); } break; + case 'TabShift': case 'ArrowLeft': if (this._selectedCells) { this._selectedCol = Math.max(0, this._selectedCol - 1); diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx index e6acff061..daffdf1f5 100644 --- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx +++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx @@ -21,11 +21,11 @@ import DOMPurify from 'dompurify'; */ export interface SchemaCellFieldProps { + Doc: Doc; contents: FieldType | undefined; fieldContents?: FieldViewProps; editing?: boolean; oneLine?: boolean; - Document: Doc; fieldKey: string; // eslint-disable-next-line no-use-before-define refSelectModeInfo: { enabled: boolean; currEditing: SchemaCellField | undefined }; @@ -55,7 +55,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro }); //must be moved to end of batch or else other docs aren't loaded, so render as d-1 in function } - get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore + get docIndex(){return DocumentView.getDocViewIndex(this._props.Doc);} // prettier-ignore get selfRefPattern() { return `d${this.docIndex}.${this._props.fieldKey}`; @@ -86,15 +86,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro editing => { if (editing) { this.setupRefSelect(this.refSelectConditionMet); - setTimeout(() => { - if (this._inputref?.innerText.startsWith('=') || this._inputref?.innerText.startsWith(':=')) { - this._overlayDisposer?.(); - this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 }); - this._props.highlightCells?.(this._unrenderedContent); - this.setContent(this._unrenderedContent); - setTimeout(() => this.setCursorPosition(this._unrenderedContent.length)); - } - }); } else { this._overlayDisposer?.(); this._overlayDisposer = undefined; @@ -192,6 +183,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro setIsFocused = (value: boolean) => { const wasFocused = this._editing; this._editing = value; + this._editing && setTimeout(() => this._inputref?.focus()); return wasFocused !== this._editing; }; @@ -272,8 +264,6 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro @action onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { - if (e.nativeEvent.defaultPrevented) return; // hack .. DashFieldView grabs native events, but react ignores stoppedPropagation and preventDefault, so we need to check it here - switch (e.key) { case 'Tab': e.stopPropagation(); @@ -284,9 +274,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro break; case 'Enter': e.stopPropagation(); - if (!e.ctrlKey) { - this.finalizeEdit(e.shiftKey, false, true); - } + !e.ctrlKey && this.finalizeEdit(e.shiftKey, false, true); break; case 'Escape': e.stopPropagation(); @@ -297,7 +285,7 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro case 'ArrowLeft': case 'ArrowRight': // prettier-ignore e.stopPropagation(); - setTimeout(() => this.setupRefSelect(this.refSelectConditionMet), 0); + setTimeout(() => this.setupRefSelect(this.refSelectConditionMet)); break; case ' ': { @@ -306,18 +294,14 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro setTimeout(() => { this.setContent(this._unrenderedContent); setTimeout(() => this.setCursorPosition(cursorPos)); - }, 0); + }); } break; - case 'u': // for some reason 'u' otherwise exits the editor - e.stopPropagation(); - break; case 'Shift': case 'Alt': case 'Meta': case 'Control': - case ':': // prettier-ignore - break; + case ':': default: break; } @@ -361,12 +345,9 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro <div contentEditable className="schemaField-editing" - ref={r => { - this._inputref = r; - }} - style={{ cursor: 'text', outline: 'none', overflow: 'auto', minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20 }} + ref={r => (this._inputref = r)} + style={{ minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20 }} onBlur={() => (this._props.refSelectModeInfo.enabled ? setTimeout(() => this.setIsFocused(true), 1000) : this.finalizeEdit(false, true, false))} - autoFocus onInput={this.onChange} onKeyDown={this.onKeyDown} onPointerDown={e => { @@ -383,14 +364,37 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro ); }; + onFocus = () => { + if (this._inputref?.innerText.startsWith('=') || this._inputref?.innerText.startsWith(':=')) { + this._overlayDisposer?.(); + this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 }); + this._props.highlightCells?.(this._unrenderedContent); + this.setContent(this._unrenderedContent); + setTimeout(() => this.setCursorPosition(this._unrenderedContent.length)); + } + }; + + onBlur = action(() => { + this._editing = false; + }); + render() { const gval = this._props.GetValue()?.replace(/\n/g, '\\r\\n'); if (this._editing && gval !== undefined) { - return <div className={`editableView-container-editing${this._props.oneLine ? '-oneLine' : ''}`}>{this.renderEditor()}</div>; + return ( + <div + className={`editableView-container-editing${this._props.oneLine ? '-oneLine' : ''}`} // + onFocus={this.onFocus} + onBlur={this.onBlur}> + {this.renderEditor()} + </div> + ); } else return this._props.contents instanceof ObjectField ? null : ( <div className={`editableView-container-editing${this._props.oneLine ? '-oneLine' : ''}`} + onFocus={this.onFocus} + onBlur={this.onBlur} style={{ minHeight: '10px', whiteSpace: this._props.oneLine ? 'nowrap' : 'pre-line', diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index da203abfa..c9853fab0 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -171,7 +171,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() { isolatedSelection={this.isolatedSelection} key={key} rowSelected={this._props.isSelected} - Document={this.Document} + Doc={this.Document} col={index} fieldKey={key} allowCRs={false} // to enter text with new lines, must use \n diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index d404378eb..e6fe46638 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -40,7 +40,7 @@ import { SchemaCellField } from './SchemaCellField'; */ export interface SchemaTableCellProps { - Document: Doc; + Doc: Doc; col: number; deselectCell: () => void; selectCell: (doc: Doc, col: number, shift: boolean, ctrl: boolean) => void; @@ -71,7 +71,7 @@ export interface SchemaTableCellProps { } function selectedCell(props: SchemaTableCellProps) { - return props.isRowActive() && props.selectedCol() === props.col && props.selectedCells()?.filter(d => d === props.Document)?.length; + return props.isRowActive() && props.selectedCol() === props.col && props.selectedCells()?.filter(d => d === props.Doc)?.length; } @observer @@ -84,11 +84,11 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro makeObservable(this); } - get docIndex(){return DocumentView.getDocViewIndex(this._props.Document);} // prettier-ignore + get docIndex(){return DocumentView.getDocViewIndex(this._props.Doc);} // prettier-ignore get isDefault(){return SchemaColumnHeader.isDefaultField(this._props.fieldKey);} // prettier-ignore - get lockedInteraction(){return (this.isDefault || this._props.Document._lockedSchemaEditing);} // prettier-ignore + get lockedInteraction(){return (this.isDefault || this._props.Doc._lockedSchemaEditing);} // prettier-ignore get backgroundColor() { if (this.lockedInteraction) { @@ -102,7 +102,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro return true; }; public static renderProps(props: SchemaTableCellProps) { - const { Document, fieldKey, getFinfo, columnWidth, isRowActive } = props; + const { Doc: Document, fieldKey, /* getFinfo,*/ columnWidth, isRowActive } = props; let protoCount = 0; let doc: Doc | undefined = Document; while (doc) { @@ -186,7 +186,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro return ( <div className="schemacell-edit-wrapper" - // onContextMenu={} + tabIndex={1} style={{ color, textDecoration, @@ -196,7 +196,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro <SchemaCellField fieldKey={this._props.fieldKey} refSelectModeInfo={this._props.refSelectModeInfo} - Document={this._props.Document} + Doc={this._props.Doc} highlightCells={(text: string) => this._props.highlightCells(this.adjustSelfReference(text))} getCells={(text: string) => this._props.eqHighlightFunc(this.adjustSelfReference(text))} ref={r => selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true)} @@ -224,7 +224,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro get getCellType() { const columnTypeStr = this._props.getFinfo(this._props.fieldKey)?.fieldType; - const cellValue = this._props.Document[this._props.fieldKey]; + const cellValue = this._props.Doc[this._props.fieldKey]; if (cellValue instanceof ImageField) return ColumnType.Image; if (cellValue instanceof DateField) return ColumnType.Date; @@ -252,15 +252,15 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro const sides: Array<string | undefined> = []; sides[0] = selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // left sides[1] = selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // right - sides[2] = !this._props.isolatedSelection(this._props.Document)[0] && selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // top - sides[3] = !this._props.isolatedSelection(this._props.Document)[1] && selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // bottom + sides[2] = !this._props.isolatedSelection(this._props.Doc)[0] && selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // top + sides[3] = !this._props.isolatedSelection(this._props.Doc)[1] && selectedCell(this._props) ? `solid 2px ${Colors.MEDIUM_BLUE}` : undefined; // bottom return sides; } render() { return ( <div - className="schema-table-cell" + className={`schema-table-cell${selectedCell(this._props) ? '-selected' : ''}`} onContextMenu={e => StopEvent(e)} onPointerDown={action(e => { if (this.lockedInteraction) { @@ -272,7 +272,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro if (this._props.refSelectModeInfo.enabled && !selectedCell(this._props)) { e.stopPropagation(); e.preventDefault(); - this._props.selectReference(this._props.Document, this._props.col); + this._props.selectReference(this._props.Doc, this._props.col); return; } @@ -280,9 +280,9 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro const ctrl: boolean = e.ctrlKey; if (this._props.isRowActive?.()) { if (selectedCell(this._props) && ctrl) { - this._props.selectCell(this._props.Document, this._props.col, shift, ctrl); + this._props.selectCell(this._props.Doc, this._props.col, shift, ctrl); e.stopPropagation(); - } else !selectedCell(this._props) && this._props.selectCell(this._props.Document, this._props.col, shift, ctrl); + } else !selectedCell(this._props) && this._props.selectCell(this._props.Doc, this._props.col, shift, ctrl); } })} style={{ @@ -321,8 +321,8 @@ export class SchemaImageCell extends ObservableReactComponent<SchemaTableCellPro } get url() { - const field = Cast(this._props.Document[this._props.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc - const alts = DocListCast(this._props.Document[this._props.fieldKey + '_alternates']); // retrieve alternate documents that may be rendered as alternate images + const field = Cast(this._props.Doc[this._props.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc + const alts = DocListCast(this._props.Doc[this._props.fieldKey + '_alternates']); // retrieve alternate documents that may be rendered as alternate images const altpaths = alts .map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url) .filter(url => url) @@ -359,7 +359,7 @@ export class SchemaImageCell extends ObservableReactComponent<SchemaTableCellPro }; render() { - const aspect = Doc.NativeAspect(this._props.Document); // aspect ratio + const aspect = Doc.NativeAspect(this._props.Doc); // aspect ratio // let width = Math.max(75, this._props.columnWidth); // get a with that is no smaller than 75px // const height = Math.max(75, width / aspect); // get a height either proportional to that or 75 px const height = this._props.rowHeight() ? this._props.rowHeight() - (this._props.padding || 6) * 2 : undefined; @@ -379,7 +379,7 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp @observable _pickingDate: boolean = false; @computed get date(): DateField { // if the cell is a date field, cast then contents to a date. Otherrwwise, make the contents undefined. - return DateCast(this._props.Document[this._props.fieldKey]); + return DateCast(this._props.Doc[this._props.fieldKey]); } handleChange = undoable((date: Date | null) => { @@ -388,7 +388,7 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp // this.applyToDoc(this._document, this._props.row, this._props.col, script.run); // } else { // ^ DateCast is always undefined for some reason, but that is what the field should be set to - date && (this._props.Document[this._props.fieldKey] = new DateField(date)); + date && (this._props.Doc[this._props.fieldKey] = new DateField(date)); // } }, 'date change'); @@ -396,10 +396,10 @@ export class SchemaDateCell extends ObservableReactComponent<SchemaTableCellProp const { pointerEvents } = SchemaTableCell.renderProps(this._props); return ( <> - <div style={{ pointerEvents: 'none' }}> + <div style={{ pointerEvents: 'none' }} tabIndex={1}> <DatePicker dateFormat="Pp" selected={this.date?.date ?? Date.now()} onChange={emptyFunction} /> </div> - {pointerEvents === 'none' ? null : ( + {pointerEvents === 'none' || !selectedCell(this._props) ? null : ( <Popup icon={<FontAwesomeIcon size="xs" icon="caret-down" />} size={Size.XSMALL} @@ -451,11 +451,11 @@ export class SchemaBoolCell extends ObservableReactComponent<SchemaTableCellProp onPointerDown={e => e.stopPropagation()} style={{ marginRight: 4 }} type="checkbox" - checked={BoolCast(this._props.Document[this._props.fieldKey])} + checked={BoolCast(this._props.Doc[this._props.fieldKey])} onChange={undoable((value: React.ChangeEvent<HTMLInputElement> | undefined) => { if ((value?.nativeEvent as MouseEvent | PointerEvent).shiftKey) { this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + (value?.target?.checked.toString() ?? '')); - } else Doc.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + (value?.target?.checked.toString() ?? '')); + } else Doc.SetField(this._props.Doc, this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + (value?.target?.checked.toString() ?? '')); }, 'set bool cell')} /> @@ -463,14 +463,14 @@ export class SchemaBoolCell extends ObservableReactComponent<SchemaTableCellProp contents="" fieldContents={fieldProps} editing={selectedCell(this._props) ? undefined : false} - GetValue={() => Field.toKeyValueString(this._props.Document, this._props.fieldKey)} + GetValue={() => Field.toKeyValueString(this._props.Doc, this._props.fieldKey)} SetValue={undoable((value: string, shiftDown?: boolean, enterKey?: boolean) => { if (shiftDown && enterKey) { this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), value); this._props.finishEdit?.(); return true; } - const set = Doc.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), value, Doc.IsDataProto(this._props.Document) ? true : undefined); + const set = Doc.SetField(this._props.Doc, this._props.fieldKey.replace(/^_/, ''), value, Doc.IsDataProto(this._props.Doc) ? true : undefined); this._props.finishEdit?.(); return set; }, 'set bool cell')} @@ -494,14 +494,22 @@ export class SchemaEnumerationCell extends ObservableReactComponent<SchemaTableC <div style={{ width: '100%' }}> <Select styles={{ + dropdownIndicator: base => ({ + ...base, + display: selectedCell(this._props) ? 'unset' : 'none', + }), container: base => ({ ...base, height: 20, + border: 'unset !important', + pointerEvents: selectedCell(this._props) ? 'all' : 'none', }), control: base => ({ ...base, height: 20, minHeight: 20, + border: 'unset !important', + background: selectedCell(this._props) ? 'lightgray' : undefined, }), placeholder: base => ({ ...base, @@ -517,6 +525,7 @@ export class SchemaEnumerationCell extends ObservableReactComponent<SchemaTableC ...base, height: 20, transform: 'scale(0.75)', + border: 'unset !important', }), menuPortal: base => ({ ...base, @@ -529,10 +538,10 @@ export class SchemaEnumerationCell extends ObservableReactComponent<SchemaTableC }} menuPortalTarget={this._props.menuTarget} menuPosition="absolute" - placeholder={StrCast(this._props.Document[this._props.fieldKey], 'select...')} + placeholder={StrCast(this._props.Doc[this._props.fieldKey], 'select...')} options={options} isMulti={false} - onChange={val => Doc.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), `"${val?.value ?? ''}"`)} + onChange={val => Doc.SetField(this._props.Doc, this._props.fieldKey.replace(/^_/, ''), `"${val?.value ?? ''}"`)} /> </div> </div> |
