@fgv/ts-app-shell 5.1.0-12 → 5.1.0-15

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.
@@ -29,7 +29,7 @@
29
29
  */
30
30
  import React, { useCallback, useEffect, useRef, useState } from 'react';
31
31
  import { StarIcon as StarIconOutline } from '@heroicons/react/24/outline';
32
- import { StarIcon as StarIconSolid, ExclamationTriangleIcon, BuildingLibraryIcon, ShieldCheckIcon, ShieldExclamationIcon, ArrowDownTrayIcon, PencilSquareIcon, ArrowsPointingInIcon, TrashIcon, FolderPlusIcon, ArchiveBoxArrowDownIcon, FolderOpenIcon, ArrowUpTrayIcon, PlusIcon, ChevronRightIcon } from '@heroicons/react/20/solid';
32
+ import { StarIcon as StarIconSolid, ExclamationTriangleIcon, BuildingLibraryIcon, BuildingStorefrontIcon, ShieldCheckIcon, ShieldExclamationIcon, ArrowDownTrayIcon, PencilSquareIcon, ArrowsPointingInIcon, TrashIcon, FolderPlusIcon, ArchiveBoxArrowDownIcon, FolderOpenIcon, ArrowUpTrayIcon, PlusIcon, ChevronRightIcon } from '@heroicons/react/20/solid';
33
33
  import { renderStatusBadge } from '../badge';
34
34
  // ============================================================================
35
35
  // Context Menu (internal)
@@ -82,7 +82,7 @@ function useLongPress(onLongPress) {
82
82
  // CollectionRow (internal)
83
83
  // ============================================================================
84
84
  function CollectionRow(props) {
85
- var _a;
85
+ var _a, _b, _c;
86
86
  const { collection, onToggleVisibility, onSetDefault, onDelete, onExport, onUnlock, onRename, onMerge, borderColorClass, onContextMenu, isHiddenRow } = props;
87
87
  const displayName = (_a = collection.name) !== null && _a !== void 0 ? _a : collection.id;
88
88
  const handleContextMenu = useCallback((e) => {
@@ -113,8 +113,7 @@ function CollectionRow(props) {
113
113
  : 'Set as default collection for new items', "aria-label": collection.isDefault ? `${displayName} is default` : `Set ${displayName} as default`, "aria-pressed": collection.isDefault }, collection.isDefault ? (React.createElement(StarIconSolid, { className: "w-4 h-4" })) : (React.createElement(StarIconOutline, { className: "w-4 h-4" })))),
114
114
  collection.hasConflict && (React.createElement("span", { className: "shrink-0 text-status-warning-strong cursor-default", title: "An encrypted copy of this collection from another storage root has the same ID. Go to Settings \u2192 Storage to resolve the conflict.", "aria-label": `Conflict: encrypted shadow for ${displayName}` },
115
115
  React.createElement(ExclamationTriangleIcon, { className: "w-4 h-4" }))),
116
- !collection.isMutable && (React.createElement("span", { className: "shrink-0 text-muted", title: "Built-in collection (read-only)" },
117
- React.createElement(BuildingLibraryIcon, { className: "w-4 h-4" }))),
116
+ !collection.isMutable && (React.createElement("span", { className: "shrink-0 text-muted", title: (_b = collection.readOnlyLabel) !== null && _b !== void 0 ? _b : 'Built-in collection (read-only)' }, collection.isDeletable ? (React.createElement(BuildingStorefrontIcon, { className: "w-4 h-4" })) : (React.createElement(BuildingLibraryIcon, { className: "w-4 h-4" })))),
118
117
  collection.isProtected &&
119
118
  (collection.isUnlocked || !onUnlock ? (React.createElement("span", { className: `shrink-0 ${collection.isUnlocked ? 'text-status-success-icon' : 'text-muted'}`, title: collection.isUnlocked ? 'Protected (unlocked)' : 'Protected (locked)' }, collection.isUnlocked ? (React.createElement(ShieldCheckIcon, { className: "w-4 h-4" })) : (React.createElement(ShieldExclamationIcon, { className: "w-4 h-4" })))) : (React.createElement("button", { onClick: (e) => {
120
119
  e.stopPropagation();
@@ -140,12 +139,12 @@ function CollectionRow(props) {
140
139
  onMerge(collection.id);
141
140
  }, className: "shrink-0 w-5 h-5 flex items-center justify-center text-faint hover:text-brand-accent transition-colors", title: `Merge ${displayName} into another collection`, "aria-label": `Merge ${displayName}` },
142
141
  React.createElement(ArrowsPointingInIcon, { className: "w-4 h-4" }))),
143
- collection.isMutable && onDelete && (React.createElement("button", { onClick: (e) => {
142
+ (collection.isMutable || collection.isDeletable) && onDelete && (React.createElement("button", { onClick: (e) => {
144
143
  e.stopPropagation();
145
144
  onDelete(collection.id);
146
145
  }, className: "shrink-0 w-5 h-5 flex items-center justify-center text-faint hover:text-status-error-icon transition-colors", title: `Remove ${displayName}`, "aria-label": `Remove ${displayName}` },
147
146
  React.createElement(TrashIcon, { className: "w-4 h-4" }))),
148
- !collection.isMutable && React.createElement("span", { className: "text-xs text-muted" }, "(built-in)"))));
147
+ !collection.isMutable && (React.createElement("span", { className: "text-xs text-muted" }, (_c = collection.readOnlyLabel) !== null && _c !== void 0 ? _c : '(built-in)')))));
149
148
  }
150
149
  // ============================================================================
151
150
  // CollectionSection
@@ -49,6 +49,17 @@ export interface ICollectionRowItem {
49
49
  readonly sourceName?: string;
50
50
  /** Optional badge rendered alongside the collection name */
51
51
  readonly badge?: ICollectionBadge;
52
+ /**
53
+ * Label shown for immutable collections. Defaults to `"(built-in)"` when
54
+ * omitted. Set to e.g. `"(trading post)"` for imported read-only content.
55
+ */
56
+ readonly readOnlyLabel?: string;
57
+ /**
58
+ * When true, the collection can be deleted even though it is not mutable.
59
+ * Use for user-imported read-only content (e.g., Trading Post collections)
60
+ * that the user should be able to remove but not edit.
61
+ */
62
+ readonly isDeletable?: boolean;
52
63
  }
53
64
  /**
54
65
  * Props for the CollectionSection component.
@@ -118,7 +118,7 @@ function useLongPress(onLongPress) {
118
118
  // CollectionRow (internal)
119
119
  // ============================================================================
120
120
  function CollectionRow(props) {
121
- var _a;
121
+ var _a, _b, _c;
122
122
  const { collection, onToggleVisibility, onSetDefault, onDelete, onExport, onUnlock, onRename, onMerge, borderColorClass, onContextMenu, isHiddenRow } = props;
123
123
  const displayName = (_a = collection.name) !== null && _a !== void 0 ? _a : collection.id;
124
124
  const handleContextMenu = (0, react_1.useCallback)((e) => {
@@ -149,8 +149,7 @@ function CollectionRow(props) {
149
149
  : 'Set as default collection for new items', "aria-label": collection.isDefault ? `${displayName} is default` : `Set ${displayName} as default`, "aria-pressed": collection.isDefault }, collection.isDefault ? (react_1.default.createElement(solid_1.StarIcon, { className: "w-4 h-4" })) : (react_1.default.createElement(outline_1.StarIcon, { className: "w-4 h-4" })))),
150
150
  collection.hasConflict && (react_1.default.createElement("span", { className: "shrink-0 text-status-warning-strong cursor-default", title: "An encrypted copy of this collection from another storage root has the same ID. Go to Settings \u2192 Storage to resolve the conflict.", "aria-label": `Conflict: encrypted shadow for ${displayName}` },
151
151
  react_1.default.createElement(solid_1.ExclamationTriangleIcon, { className: "w-4 h-4" }))),
152
- !collection.isMutable && (react_1.default.createElement("span", { className: "shrink-0 text-muted", title: "Built-in collection (read-only)" },
153
- react_1.default.createElement(solid_1.BuildingLibraryIcon, { className: "w-4 h-4" }))),
152
+ !collection.isMutable && (react_1.default.createElement("span", { className: "shrink-0 text-muted", title: (_b = collection.readOnlyLabel) !== null && _b !== void 0 ? _b : 'Built-in collection (read-only)' }, collection.isDeletable ? (react_1.default.createElement(solid_1.BuildingStorefrontIcon, { className: "w-4 h-4" })) : (react_1.default.createElement(solid_1.BuildingLibraryIcon, { className: "w-4 h-4" })))),
154
153
  collection.isProtected &&
155
154
  (collection.isUnlocked || !onUnlock ? (react_1.default.createElement("span", { className: `shrink-0 ${collection.isUnlocked ? 'text-status-success-icon' : 'text-muted'}`, title: collection.isUnlocked ? 'Protected (unlocked)' : 'Protected (locked)' }, collection.isUnlocked ? (react_1.default.createElement(solid_1.ShieldCheckIcon, { className: "w-4 h-4" })) : (react_1.default.createElement(solid_1.ShieldExclamationIcon, { className: "w-4 h-4" })))) : (react_1.default.createElement("button", { onClick: (e) => {
156
155
  e.stopPropagation();
@@ -176,12 +175,12 @@ function CollectionRow(props) {
176
175
  onMerge(collection.id);
177
176
  }, className: "shrink-0 w-5 h-5 flex items-center justify-center text-faint hover:text-brand-accent transition-colors", title: `Merge ${displayName} into another collection`, "aria-label": `Merge ${displayName}` },
178
177
  react_1.default.createElement(solid_1.ArrowsPointingInIcon, { className: "w-4 h-4" }))),
179
- collection.isMutable && onDelete && (react_1.default.createElement("button", { onClick: (e) => {
178
+ (collection.isMutable || collection.isDeletable) && onDelete && (react_1.default.createElement("button", { onClick: (e) => {
180
179
  e.stopPropagation();
181
180
  onDelete(collection.id);
182
181
  }, className: "shrink-0 w-5 h-5 flex items-center justify-center text-faint hover:text-status-error-icon transition-colors", title: `Remove ${displayName}`, "aria-label": `Remove ${displayName}` },
183
182
  react_1.default.createElement(solid_1.TrashIcon, { className: "w-4 h-4" }))),
184
- !collection.isMutable && react_1.default.createElement("span", { className: "text-xs text-muted" }, "(built-in)"))));
183
+ !collection.isMutable && (react_1.default.createElement("span", { className: "text-xs text-muted" }, (_c = collection.readOnlyLabel) !== null && _c !== void 0 ? _c : '(built-in)')))));
185
184
  }
186
185
  // ============================================================================
187
186
  // CollectionSection
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fgv/ts-app-shell",
3
- "version": "5.1.0-12",
3
+ "version": "5.1.0-15",
4
4
  "description": "Shared React UI primitives for application shells: column cascade, sidebar, toast/log messages, command palette, keybinding registry",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -17,8 +17,8 @@
17
17
  "dependencies": {
18
18
  "@heroicons/react": "~2.2.0",
19
19
  "tslib": "^2.8.1",
20
- "@fgv/ts-utils": "5.1.0-12",
21
- "@fgv/ts-extras": "5.1.0-12"
20
+ "@fgv/ts-utils": "5.1.0-15",
21
+ "@fgv/ts-extras": "5.1.0-15"
22
22
  },
23
23
  "peerDependencies": {
24
24
  "react": ">=18.0.0",
@@ -51,8 +51,8 @@
51
51
  "@rushstack/heft-jest-plugin": "1.2.6",
52
52
  "@testing-library/dom": "^10.4.0",
53
53
  "@rushstack/heft-node-rig": "2.11.27",
54
- "@fgv/ts-utils-jest": "5.1.0-12",
55
- "@fgv/heft-dual-rig": "5.1.0-12"
54
+ "@fgv/ts-utils-jest": "5.1.0-15",
55
+ "@fgv/heft-dual-rig": "5.1.0-15"
56
56
  },
57
57
  "exports": {
58
58
  ".": {