@termix-ssh/plugin-sdk 1.0.19 → 1.0.20

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.20
4
+
5
+ Plugin API 1.12.0.
6
+
7
+ ### Added
8
+
9
+ - `columns` and `onColumns` on `ViewToggle` show a cards per row picker: Auto fits as many as the pane has room for, or pick 1 to 6
10
+ - `size` and `minCardWidth` on `DataView`, so a card grid follows that pick, and the `GridSize` type
11
+ - `usePluginPanelView` also keeps `columns`, the cards per row pick, with `setColumns`
12
+
3
13
  ## 1.0.19
4
14
 
5
15
  Plugin API 1.11.0.
package/PLUGIN-GUIDE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Termix plugin guide
2
2
 
3
- SDK 1.0.19 | Plugin API 1.11.0
3
+ SDK 1.0.20 | Plugin API 1.12.0
4
4
 
5
5
  This guide is for anyone, person or AI coding tool, building a Termix plugin. It ships inside
6
6
  `@termix-ssh/plugin-sdk`, so the copy in your `node_modules` always matches the SDK you have installed.
@@ -643,6 +643,9 @@ exports with props is `ui.api.txt` in the Termix repo
643
643
  `PanePrompt` for small prompts.
644
644
  - Every tab or panel sits in `PanelShell`. Lists use `PanelList` and `ListRow`, add with `AddButton`,
645
645
  forms end with `FormFooter`, empty lists show `EmptyState`.
646
+ - Card grids use `DataView` with `ViewToggle`. Pass `columns` and `onColumns` to `ViewToggle` and the same
647
+ value as `size` to `DataView`, so users can pick Auto (as many as fit) or a fixed number of cards per
648
+ row. `usePluginPanelView` keeps the choice as `columns`. Older Termix versions ignore both props.
646
649
  - Forms: `TextField`, `NumberField`, `SelectField`, `SwitchRow`, `SecretField`, `SettingRow` and friends.
647
650
  - Host sessions use `ConnectionGate` for the whole connect flow (host keys, TOTP, passphrases, errors).
648
651
  - Mobile: check `useIsMobile()` and give small screens a layout that works. The desktop app always uses the
@@ -1426,17 +1426,21 @@ export declare function usePluginUiPreferences<T extends Record<string, unknown>
1426
1426
  values: T;
1427
1427
  set: <K extends keyof T & string>(key: K, value: T[K] | null) => void;
1428
1428
  };
1429
+ type PanelGridSize = "auto" | "1" | "2" | "3" | "4" | "5" | "6";
1429
1430
  /**
1430
- * Grid or list and row density for one of this plugin's views, kept in its
1431
- * Appearance area as `<prefix>viewMode` and `<prefix>density`. Declare those
1432
- * keys in contributes.uiPresets so each preset level can pick a default.
1431
+ * Grid or list, row density and cards per row for one of this plugin's
1432
+ * views, kept in its Appearance area as `<prefix>viewMode`, `<prefix>density`
1433
+ * and `<prefix>columns`. Declare those keys in contributes.uiPresets so each
1434
+ * preset level can pick a default. Hand columns to ViewToggle and DataView.
1433
1435
  */
1434
1436
  export declare function usePluginPanelView(prefix?: string): {
1435
1437
  view: "grid" | "list";
1436
1438
  density: "comfortable" | "compact";
1437
1439
  compact: boolean;
1440
+ columns: PanelGridSize;
1438
1441
  setView: (view: "grid" | "list") => void;
1439
1442
  setDensity: (density: "comfortable" | "compact") => void;
1443
+ setColumns: (columns: PanelGridSize) => void;
1440
1444
  };
1441
1445
  export declare function useTabs(): TabsApi;
1442
1446
  /**
package/dist/frontend.js CHANGED
@@ -165,21 +165,37 @@ export function usePluginUiPreferences() {
165
165
  const bridge = requireHost();
166
166
  return bridge.usePluginUiPreferences(bridge.usePluginId());
167
167
  }
168
+ const PANEL_GRID_SIZES = [
169
+ "auto",
170
+ "1",
171
+ "2",
172
+ "3",
173
+ "4",
174
+ "5",
175
+ "6",
176
+ ];
168
177
  /**
169
- * Grid or list and row density for one of this plugin's views, kept in its
170
- * Appearance area as `<prefix>viewMode` and `<prefix>density`. Declare those
171
- * keys in contributes.uiPresets so each preset level can pick a default.
178
+ * Grid or list, row density and cards per row for one of this plugin's
179
+ * views, kept in its Appearance area as `<prefix>viewMode`, `<prefix>density`
180
+ * and `<prefix>columns`. Declare those keys in contributes.uiPresets so each
181
+ * preset level can pick a default. Hand columns to ViewToggle and DataView.
172
182
  */
173
183
  export function usePluginPanelView(prefix = "") {
174
184
  const { values, set } = usePluginUiPreferences();
175
185
  const view = values[`${prefix}viewMode`] === "list" ? "list" : "grid";
176
186
  const density = values[`${prefix}density`] === "compact" ? "compact" : "comfortable";
187
+ const saved = values[`${prefix}columns`];
188
+ const columns = typeof saved === "string" && PANEL_GRID_SIZES.includes(saved)
189
+ ? saved
190
+ : "auto";
177
191
  return {
178
192
  view,
179
193
  density,
180
194
  compact: density === "compact",
195
+ columns,
181
196
  setView: (next) => set(`${prefix}viewMode`, next),
182
197
  setDensity: (next) => set(`${prefix}density`, next),
198
+ setColumns: (next) => set(`${prefix}columns`, next),
183
199
  };
184
200
  }
185
201
  export function useTabs() {
@@ -29,7 +29,7 @@ import {
29
29
  sortPlugins,
30
30
  uploadEntry,
31
31
  youtubeEmbedUrl
32
- } from "./chunk-446UEDSK.js";
32
+ } from "./chunk-CITUENSU.js";
33
33
  import {
34
34
  ArrowDownWideNarrow,
35
35
  BookOpen,
@@ -38,7 +38,6 @@ import {
38
38
  Check,
39
39
  ChevronLeft,
40
40
  ChevronRight,
41
- Columns3,
42
41
  DEVELOPER_MODE_CHANGED_EVENT,
43
42
  Database,
44
43
  DocsLink,
@@ -47,6 +46,7 @@ import {
47
46
  Facts,
48
47
  FakeSwitch,
49
48
  FlaskConical,
49
+ GRID_SIZES,
50
50
  Globe,
51
51
  GroupHeading,
52
52
  InlineView,
@@ -107,7 +107,7 @@ import {
107
107
  updatePlugin,
108
108
  uploadPlugin,
109
109
  useConfirm
110
- } from "./chunk-LQKK2JJA.js";
110
+ } from "./chunk-EYONBBRJ.js";
111
111
  import "./chunk-7LEJ3HYF.js";
112
112
  import {
113
113
  __toESM,
@@ -1845,7 +1845,6 @@ function usePluginsManager() {
1845
1845
 
1846
1846
  // src/ui/plugins/PluginsTab.tsx
1847
1847
  import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1848
- var GRID_SIZES = ["auto", "2", "3", "4", "5", "6"];
1849
1848
  function useStoredChoice(key, allowed, fallback) {
1850
1849
  const [value, setValue] = useState5(() => {
1851
1850
  try {
@@ -2075,45 +2074,15 @@ function LayoutControls({
2075
2074
  onView,
2076
2075
  onColumns
2077
2076
  }) {
2078
- const { t } = useTranslation7();
2079
- return /* @__PURE__ */ jsxs6(Fragment4, { children: [
2080
- layout.view === "grid" && /* @__PURE__ */ jsxs6(
2081
- Select,
2082
- {
2083
- value: layout.columns,
2084
- onValueChange: (v) => onColumns(v),
2085
- children: [
2086
- /* @__PURE__ */ jsxs6(
2087
- SelectTrigger,
2088
- {
2089
- size: "sm",
2090
- className: "w-auto gap-1.5 text-xs",
2091
- title: t("plugins.manager.columns.title"),
2092
- "aria-label": t("plugins.manager.columns.title"),
2093
- children: [
2094
- /* @__PURE__ */ jsx6(Columns3, { className: "size-3.5 text-muted-foreground" }),
2095
- /* @__PURE__ */ jsx6(SelectValue, {})
2096
- ]
2097
- }
2098
- ),
2099
- /* @__PURE__ */ jsx6(SelectContent, { children: GRID_SIZES.map((size) => /* @__PURE__ */ jsx6(SelectItem, { value: size, className: "text-xs", children: size === "auto" ? t("plugins.manager.columns.auto") : t("plugins.manager.columns.count", { count: Number(size) }) }, size)) })
2100
- ]
2101
- }
2102
- ),
2103
- /* @__PURE__ */ jsx6(ViewToggle, { view: layout.view, onView })
2104
- ] });
2105
- }
2106
- function gridStyle(columns) {
2107
- if (columns === "auto") {
2108
- return {
2109
- gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 400px), 1fr))"
2110
- };
2111
- }
2112
- const n = Number(columns);
2113
- const gaps = (n - 1) * 12;
2114
- return {
2115
- gridTemplateColumns: `repeat(auto-fill, minmax(max(220px, calc((100% - ${gaps}px) / ${n} - 0.5px)), 1fr))`
2116
- };
2077
+ return /* @__PURE__ */ jsx6(
2078
+ ViewToggle,
2079
+ {
2080
+ view: layout.view,
2081
+ onView,
2082
+ columns: layout.columns,
2083
+ onColumns
2084
+ }
2085
+ );
2117
2086
  }
2118
2087
  function PluginCollection({
2119
2088
  plugins,
@@ -2137,7 +2106,20 @@ function PluginCollection({
2137
2106
  }
2138
2107
  );
2139
2108
  }
2140
- return /* @__PURE__ */ jsx6("div", { className: "grid gap-3", style: gridStyle(layout.columns), children: plugins.map((p) => /* @__PURE__ */ jsx6("div", { className: "flex flex-col *:flex-1", children: renderCard(p) }, p.id)) });
2109
+ return /* @__PURE__ */ jsx6(
2110
+ DataView,
2111
+ {
2112
+ items: plugins,
2113
+ view: "grid",
2114
+ getKey: (p) => p.id,
2115
+ renderCard,
2116
+ columns: {},
2117
+ size: layout.columns,
2118
+ minCardWidth: 400,
2119
+ listColumns,
2120
+ empty: null
2121
+ }
2122
+ );
2141
2123
  }
2142
2124
  function NameCell({ plugin, muted }) {
2143
2125
  return /* @__PURE__ */ jsxs6("div", { className: "flex min-w-0 items-center gap-2", children: [
@@ -6,8 +6,9 @@ import {
6
6
  Plus,
7
7
  Trash,
8
8
  cn,
9
+ gridSizeStyle,
9
10
  useAreaPreferences
10
- } from "./chunk-LQKK2JJA.js";
11
+ } from "./chunk-EYONBBRJ.js";
11
12
  import {
12
13
  isElectron
13
14
  } from "./chunk-7LEJ3HYF.js";
@@ -2219,6 +2220,8 @@ function DataView({
2219
2220
  getKey,
2220
2221
  renderCard,
2221
2222
  columns,
2223
+ size,
2224
+ minCardWidth,
2222
2225
  listColumns,
2223
2226
  onRowClick,
2224
2227
  isRowActive,
@@ -2229,7 +2232,19 @@ function DataView({
2229
2232
  return /* @__PURE__ */ jsx3("div", { className: "flex flex-1 items-center justify-center", children: empty });
2230
2233
  }
2231
2234
  if (view === "grid") {
2232
- return /* @__PURE__ */ jsx3("div", { className: cn("grid", PANEL.gap, gridClass(columns), className), children: items.map((item) => /* @__PURE__ */ jsx3("div", { children: renderCard(item) }, getKey(item))) });
2235
+ return /* @__PURE__ */ jsx3(
2236
+ "div",
2237
+ {
2238
+ className: cn(
2239
+ "grid",
2240
+ PANEL.gap,
2241
+ !size && gridClass(columns),
2242
+ className
2243
+ ),
2244
+ style: size ? gridSizeStyle(size, minCardWidth) : void 0,
2245
+ children: items.map((item) => /* @__PURE__ */ jsx3("div", { className: "flex flex-col *:flex-1", children: renderCard(item) }, getKey(item)))
2246
+ }
2247
+ );
2233
2248
  }
2234
2249
  const template = listColumns.map((c) => c.width).join(" ");
2235
2250
  const rowHeight = density === "compact" ? "h-7" : "h-9";