@revisium/schema-toolkit-ui 0.6.11 → 0.6.13

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/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import * as mobx from "mobx";
2
2
  import { comparer, computed, makeAutoObservable, observable, reaction, runInAction, untracked } from "mobx";
3
3
  import { FIELD_NAME_ERROR_MESSAGE, SchemaParser, SystemSchemaIds, arr, createRowModel, createSchemaTree, createTableModel, fileSchema, generateDefaultValue, isForeignKeyValueNode, isValidFieldName, jsonPointerToSimplePath, num, obj, rowCreatedAtSchema, rowCreatedIdSchema, rowHashSchema, rowIdSchema, rowPublishedAtSchema, rowSchemaHashSchema, rowUpdatedAtSchema, rowVersionIdSchema, str, validateFormulaAgainstSchema } from "@revisium/schema-toolkit";
4
4
  import { createMobxProvider, setReactivityProvider } from "@revisium/schema-toolkit/core";
5
- import { ActionBar, Badge, Box, Button, Checkbox, Flex, HStack, HoverCard, Icon, IconButton, Image, Input, Kbd, Menu, Popover, Portal, SegmentGroup, Spinner, Text, Textarea, Tooltip as Tooltip$1, VStack, chakra } from "@chakra-ui/react";
5
+ import { ActionBar, Badge, Box, Button, Checkbox, Flex, HStack, HoverCard, Icon, IconButton, Image, Input, Kbd, Menu, Popover, Portal, SegmentGroup, Skeleton, Spinner, Text, Textarea, Tooltip as Tooltip$1, VStack, chakra } from "@chakra-ui/react";
6
6
  import { observer } from "mobx-react-lite";
7
7
  import * as React$1 from "react";
8
8
  import React, { Fragment, createContext, memo, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
@@ -2767,7 +2767,7 @@ const SHARED_STYLES = {
2767
2767
  fontSize: "inherit",
2768
2768
  fontFamily: "inherit"
2769
2769
  };
2770
- const SegmentContent = ({ segment, isHighlighted, onClick }) => {
2770
+ const SegmentContent = ({ segment, isHighlighted, isLast, onClick }) => {
2771
2771
  if (onClick) return /* @__PURE__ */ jsx(StyledButton, {
2772
2772
  type: "button",
2773
2773
  ...SHARED_STYLES,
@@ -2789,7 +2789,7 @@ const SegmentContent = ({ segment, isHighlighted, onClick }) => {
2789
2789
  ...SHARED_STYLES,
2790
2790
  color: isHighlighted ? CURRENT_COLOR : SEGMENT_COLOR,
2791
2791
  fontWeight: isHighlighted ? "600" : void 0,
2792
- cursor: isHighlighted ? "text" : "default",
2792
+ cursor: isHighlighted || isLast ? "text" : "default",
2793
2793
  "aria-current": isHighlighted ? "page" : void 0,
2794
2794
  "data-testid": segment.dataTestId,
2795
2795
  children: segment.label
@@ -2822,6 +2822,7 @@ const Breadcrumbs = ({ segments, separator = "/", dataTestId, highlightLast = tr
2822
2822
  children: /* @__PURE__ */ jsx(SegmentContent, {
2823
2823
  segment,
2824
2824
  isHighlighted: isLast && highlightLast,
2825
+ isLast,
2825
2826
  onClick: isLast ? void 0 : onSegmentClick ? () => onSegmentClick(segment, index) : void 0
2826
2827
  })
2827
2828
  }), (!isLast || editable) && /* @__PURE__ */ jsx(Flex, {
@@ -14206,6 +14207,45 @@ var MockDataSource = class {
14206
14207
  }
14207
14208
  };
14208
14209
 
14210
+ //#endregion
14211
+ //#region src/hooks/useDelayedVisibility.ts
14212
+ /**
14213
+ * Controls visibility with a show delay and minimum display time.
14214
+ *
14215
+ * - If `active` becomes false before `delayMs` elapses → never shown.
14216
+ * - If shown, stays visible for at least `minShowMs` after `active` becomes false.
14217
+ */
14218
+ function useDelayedVisibility(active, { delayMs = 150, minShowMs = 300 } = {}) {
14219
+ const [visible, setVisible] = useState(false);
14220
+ const shownAt = useRef(null);
14221
+ useEffect(() => {
14222
+ if (active) {
14223
+ const timer = setTimeout(() => {
14224
+ shownAt.current = Date.now();
14225
+ setVisible(true);
14226
+ }, delayMs);
14227
+ return () => clearTimeout(timer);
14228
+ }
14229
+ if (shownAt.current !== null) {
14230
+ const remaining = minShowMs - (Date.now() - shownAt.current);
14231
+ if (remaining > 0) {
14232
+ const timer = setTimeout(() => {
14233
+ shownAt.current = null;
14234
+ setVisible(false);
14235
+ }, remaining);
14236
+ return () => clearTimeout(timer);
14237
+ }
14238
+ shownAt.current = null;
14239
+ }
14240
+ setVisible(false);
14241
+ }, [
14242
+ active,
14243
+ delayMs,
14244
+ minShowMs
14245
+ ]);
14246
+ return visible;
14247
+ }
14248
+
14209
14249
  //#endregion
14210
14250
  //#region src/table-editor/Status/ui/CellInfoWidget.tsx
14211
14251
  const CellInfoWidget = observer(({ model }) => {
@@ -14348,17 +14388,178 @@ const ViewSettingsBadge = observer(({ model }) => {
14348
14388
  });
14349
14389
  });
14350
14390
 
14391
+ //#endregion
14392
+ //#region src/table-editor/TableEditor/ui/TableEditorSkeleton.tsx
14393
+ const HEADER_ROW_HEIGHT = 40;
14394
+ const DATA_ROW_HEIGHT = 40;
14395
+ const SKELETON_ROW_COUNT = 8;
14396
+ const COLUMN_WIDTHS = [
14397
+ 120,
14398
+ 150,
14399
+ 120,
14400
+ 100,
14401
+ 130
14402
+ ];
14403
+ const CONTENT_WIDTHS = [
14404
+ [
14405
+ 80,
14406
+ 110,
14407
+ 70,
14408
+ 60,
14409
+ 90
14410
+ ],
14411
+ [
14412
+ 100,
14413
+ 90,
14414
+ 100,
14415
+ 80,
14416
+ 110
14417
+ ],
14418
+ [
14419
+ 60,
14420
+ 130,
14421
+ 80,
14422
+ 70,
14423
+ 80
14424
+ ],
14425
+ [
14426
+ 90,
14427
+ 100,
14428
+ 60,
14429
+ 90,
14430
+ 100
14431
+ ],
14432
+ [
14433
+ 75,
14434
+ 120,
14435
+ 90,
14436
+ 55,
14437
+ 70
14438
+ ],
14439
+ [
14440
+ 110,
14441
+ 80,
14442
+ 75,
14443
+ 80,
14444
+ 120
14445
+ ],
14446
+ [
14447
+ 85,
14448
+ 140,
14449
+ 95,
14450
+ 65,
14451
+ 95
14452
+ ],
14453
+ [
14454
+ 95,
14455
+ 70,
14456
+ 110,
14457
+ 85,
14458
+ 80
14459
+ ]
14460
+ ];
14461
+ const TableEditorSkeleton = ({ breadcrumbs, onBreadcrumbClick, showCreateButton, useWindowScroll }) => /* @__PURE__ */ jsxs(Box, {
14462
+ display: "flex",
14463
+ flexDirection: "column",
14464
+ height: useWindowScroll ? void 0 : "100%",
14465
+ flex: useWindowScroll ? 1 : void 0,
14466
+ children: [/* @__PURE__ */ jsxs(Flex, {
14467
+ px: 3,
14468
+ pt: "32px",
14469
+ pb: "48px",
14470
+ alignItems: "flex-start",
14471
+ justifyContent: "space-between",
14472
+ ...useWindowScroll && {
14473
+ position: "sticky",
14474
+ top: 0,
14475
+ zIndex: 3,
14476
+ bg: "white"
14477
+ },
14478
+ children: [breadcrumbs.length > 0 ? /* @__PURE__ */ jsx(Breadcrumbs, {
14479
+ segments: breadcrumbs,
14480
+ highlightLast: false,
14481
+ onSegmentClick: onBreadcrumbClick,
14482
+ action: showCreateButton ? /* @__PURE__ */ jsx(Skeleton, {
14483
+ height: "32px",
14484
+ width: "32px",
14485
+ borderRadius: "6px"
14486
+ }) : void 0
14487
+ }) : /* @__PURE__ */ jsx(Box, {}), /* @__PURE__ */ jsxs(Flex, {
14488
+ alignItems: "center",
14489
+ gap: "8px",
14490
+ children: [
14491
+ /* @__PURE__ */ jsx(Skeleton, {
14492
+ height: "32px",
14493
+ width: "32px",
14494
+ borderRadius: "6px"
14495
+ }),
14496
+ /* @__PURE__ */ jsx(Skeleton, {
14497
+ height: "32px",
14498
+ width: "32px",
14499
+ borderRadius: "6px"
14500
+ }),
14501
+ /* @__PURE__ */ jsx(Skeleton, {
14502
+ height: "32px",
14503
+ width: "32px",
14504
+ borderRadius: "6px"
14505
+ })
14506
+ ]
14507
+ })]
14508
+ }), /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Flex, {
14509
+ height: `${HEADER_ROW_HEIGHT}px`,
14510
+ alignItems: "center",
14511
+ px: 3,
14512
+ borderBottom: "1px solid",
14513
+ borderColor: "gray.100",
14514
+ children: COLUMN_WIDTHS.map((colWidth, j) => /* @__PURE__ */ jsx(Box, {
14515
+ width: `${colWidth}px`,
14516
+ flexShrink: 0,
14517
+ children: /* @__PURE__ */ jsx(Skeleton, {
14518
+ height: "12px",
14519
+ width: "60px",
14520
+ borderRadius: "4px"
14521
+ })
14522
+ }, `h-${j}`))
14523
+ }), CONTENT_WIDTHS.slice(0, SKELETON_ROW_COUNT).map((contentWidths, i) => /* @__PURE__ */ jsx(Flex, {
14524
+ height: `${DATA_ROW_HEIGHT}px`,
14525
+ alignItems: "center",
14526
+ px: 3,
14527
+ borderBottom: "1px solid",
14528
+ borderColor: "gray.100",
14529
+ children: COLUMN_WIDTHS.map((colWidth, j) => /* @__PURE__ */ jsx(Box, {
14530
+ width: `${colWidth}px`,
14531
+ flexShrink: 0,
14532
+ children: /* @__PURE__ */ jsx(Skeleton, {
14533
+ height: "14px",
14534
+ width: `${contentWidths[j]}px`,
14535
+ borderRadius: "4px"
14536
+ })
14537
+ }, `r-${i}-c-${j}`))
14538
+ }, `r-${i}`))] })]
14539
+ });
14540
+
14351
14541
  //#endregion
14352
14542
  //#region src/table-editor/TableEditor/ui/TableEditor.tsx
14353
14543
  const noop = () => {};
14544
+ function getWriteCallbacks(isReadonly, viewModel, callbacks) {
14545
+ return {
14546
+ onDeleteRow: isReadonly ? void 0 : (id) => viewModel.deleteRows([id]),
14547
+ onDuplicateRow: isReadonly ? void 0 : callbacks.onDuplicateRow,
14548
+ onDeleteSelected: isReadonly ? void 0 : (ids) => viewModel.deleteRows(ids),
14549
+ onUploadFile: isReadonly ? void 0 : callbacks.onUploadFile
14550
+ };
14551
+ }
14354
14552
  const TableEditor = observer(({ viewModel, useWindowScroll }) => {
14355
- if (viewModel.isBootstrapping) return /* @__PURE__ */ jsx(Box, {
14356
- display: "flex",
14357
- alignItems: "center",
14358
- justifyContent: "center",
14359
- height: "100%",
14360
- children: /* @__PURE__ */ jsx(Spinner, {})
14361
- });
14553
+ const showSkeleton = useDelayedVisibility(viewModel.isBootstrapping);
14554
+ if (viewModel.isBootstrapping) {
14555
+ if (!showSkeleton) return null;
14556
+ return /* @__PURE__ */ jsx(TableEditorSkeleton, {
14557
+ breadcrumbs: viewModel.breadcrumbs,
14558
+ onBreadcrumbClick: viewModel.callbacks.onBreadcrumbClick,
14559
+ showCreateButton: !viewModel.readonly && !!viewModel.callbacks.onCreateRow,
14560
+ useWindowScroll
14561
+ });
14562
+ }
14362
14563
  const isReadonly = viewModel.readonly;
14363
14564
  const { breadcrumbs, callbacks } = viewModel;
14364
14565
  return /* @__PURE__ */ jsxs(Box, {
@@ -14419,11 +14620,8 @@ const TableEditor = observer(({ viewModel, useWindowScroll }) => {
14419
14620
  onEndReached: viewModel.loadMore,
14420
14621
  onOpenRow: callbacks.onOpenRow,
14421
14622
  onPickRow: callbacks.onPickRow,
14422
- onDeleteRow: isReadonly ? void 0 : (id) => viewModel.deleteRows([id]),
14423
- onDuplicateRow: isReadonly ? void 0 : callbacks.onDuplicateRow,
14424
- onDeleteSelected: isReadonly ? void 0 : (ids) => viewModel.deleteRows(ids),
14623
+ ...getWriteCallbacks(isReadonly, viewModel, callbacks),
14425
14624
  onSearchForeignKey: callbacks.onSearchForeignKey,
14426
- onUploadFile: isReadonly ? void 0 : callbacks.onUploadFile,
14427
14625
  onOpenFile: callbacks.onOpenFile,
14428
14626
  onCopyPath: callbacks.onCopyPath,
14429
14627
  useWindowScroll
@@ -14456,5 +14654,5 @@ const TableEditor = observer(({ viewModel, useWindowScroll }) => {
14456
14654
  });
14457
14655
 
14458
14656
  //#endregion
14459
- export { BackButton, BooleanCell, Breadcrumbs, CellFSM, CellRenderer, CellVM, CellWrapper, CloseButton, ColumnsModel, ContentEditable, CopyButton, CreateButton, CreatingEditorVM, CreatingSchemaEditor, DataRow, DateTimeCell, DeleteConfirmDialog, FieldSelect, FileCell, FilterConditionVM, FilterConditionView, FilterCore, FilterCore as FilterModel, FilterFieldType, FilterGroupVM, FilterGroupView, FilterOperator, FilterValueInput, FilterWidget, ForeignKeyCell, GrayButton, HeaderRow, JsonCard, MockDataSource, NumberCell, OPERATORS_BY_TYPE, OperatorSelect, PlusButton, ReadonlyCell, ResizeHandle, RowActionsMenu, RowCountModel, RowCountWidget, RowEditor, RowEditorVM, RowVM, SEARCH_LANGUAGES, SEARCH_TYPES, SORT_SCHEMA, SYSTEM_FIELDS, SYSTEM_FIELD_BY_REF, SYSTEM_FIELD_IDS, SchemaContext, SchemaEditorCore, SchemaTypeIds, SearchForeignKey, SearchForeignKeyVM, SearchLanguage, SearchModel, SearchType, SearchWidget, SelectionModel, SelectionToolbar, SettingsButton, SortDirectionSelect, SortFieldSelect, SortModel, SortRow, SortingsWidget, StringCell, SystemFieldId, TableEditor, TableEditorCore, TableWidget, Tooltip, UpdatingEditorVM, UpdatingSchemaEditor, ViewSettingsBadge, ViewSettingsBadgeModel, ViewerSwitcher, ViewerSwitcherMode, buildWhereClause, ensureReactivityProvider, extractColumns, getDefaultOperator, getLabelByRef, getOperatorLabel, getOperatorsForType, groupFileFields, isFileFieldGroup, operatorRequiresValue, selectDefaultColumns, typeMenuGroups, useContentEditable };
14657
+ export { BackButton, BooleanCell, Breadcrumbs, CellFSM, CellRenderer, CellVM, CellWrapper, CloseButton, ColumnsModel, ContentEditable, CopyButton, CreateButton, CreatingEditorVM, CreatingSchemaEditor, DataRow, DateTimeCell, DeleteConfirmDialog, FieldSelect, FileCell, FilterConditionVM, FilterConditionView, FilterCore, FilterCore as FilterModel, FilterFieldType, FilterGroupVM, FilterGroupView, FilterOperator, FilterValueInput, FilterWidget, ForeignKeyCell, GrayButton, HeaderRow, JsonCard, MockDataSource, NumberCell, OPERATORS_BY_TYPE, OperatorSelect, PlusButton, ReadonlyCell, ResizeHandle, RowActionsMenu, RowCountModel, RowCountWidget, RowEditor, RowEditorVM, RowVM, SEARCH_LANGUAGES, SEARCH_TYPES, SORT_SCHEMA, SYSTEM_FIELDS, SYSTEM_FIELD_BY_REF, SYSTEM_FIELD_IDS, SchemaContext, SchemaEditorCore, SchemaTypeIds, SearchForeignKey, SearchForeignKeyVM, SearchLanguage, SearchModel, SearchType, SearchWidget, SelectionModel, SelectionToolbar, SettingsButton, SortDirectionSelect, SortFieldSelect, SortModel, SortRow, SortingsWidget, StringCell, SystemFieldId, TableEditor, TableEditorCore, TableWidget, Tooltip, UpdatingEditorVM, UpdatingSchemaEditor, ViewSettingsBadge, ViewSettingsBadgeModel, ViewerSwitcher, ViewerSwitcherMode, buildWhereClause, ensureReactivityProvider, extractColumns, getDefaultOperator, getLabelByRef, getOperatorLabel, getOperatorsForType, groupFileFields, isFileFieldGroup, operatorRequiresValue, selectDefaultColumns, typeMenuGroups, useContentEditable, useDelayedVisibility };
14460
14658
  //# sourceMappingURL=index.mjs.map