@veltrixsecops/app-sdk 3.0.0 → 3.2.0

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.
@@ -127,6 +127,135 @@ interface SelectProps {
127
127
  * <Select label="Environment" value={env} onChange={setEnv} options={[{ value: 'prod', label: 'Production' }]} />
128
128
  */
129
129
  declare const Select: React.FC<SelectProps>;
130
+ type SearchBoxSize = 'sm' | 'md' | 'lg';
131
+ interface SearchBoxProps {
132
+ /** Controlled search text. */
133
+ value: string;
134
+ /** Called with the new text — debounced by `debounceMs` when set. */
135
+ onChange: (value: string) => void;
136
+ placeholder?: string;
137
+ disabled?: boolean;
138
+ size?: SearchBoxSize;
139
+ /** Debounces `onChange` by this many ms; omit (or `0`) to call on every keystroke. */
140
+ debounceMs?: number;
141
+ className?: string;
142
+ 'aria-label'?: string;
143
+ }
144
+ /**
145
+ * SearchBox — delegates to the platform's real SearchBox at render time (leading search icon,
146
+ * a clear button once there's text, optional debounce). The fallback is a bare
147
+ * `<input type="search">` wired straight to `value`/`onChange` — no icon, no debounce, no
148
+ * clear button — but functionally sufficient for typing and clearing.
149
+ *
150
+ * @example
151
+ * <SearchBox value={search} onChange={setSearch} placeholder="Search apps…" debounceMs={250} />
152
+ */
153
+ declare const SearchBox: React.FC<SearchBoxProps>;
154
+ interface PaginationProps {
155
+ /** 1-based current page. */
156
+ page: number;
157
+ pageSize: number;
158
+ totalItems: number;
159
+ onPageChange: (page: number) => void;
160
+ /** Renders a page-size selector when provided together with `pageSizeOptions`. */
161
+ onPageSizeChange?: (size: number) => void;
162
+ pageSizeOptions?: number[];
163
+ disabled?: boolean;
164
+ className?: string;
165
+ }
166
+ /**
167
+ * Pagination — delegates to the platform's real Pagination at render time: a "Showing X–Y of
168
+ * N" summary, numbered pages with ellipsis for large ranges, an optional page-size Select, and
169
+ * `aria-current="page"` on the active page — visually consistent with DataTable's built-in
170
+ * pagination footer. The fallback is a plain Prev/Next pair with "page X of Y" text.
171
+ *
172
+ * @example
173
+ * <Pagination page={page} pageSize={20} totalItems={total} onPageChange={setPage} />
174
+ */
175
+ declare const Pagination: React.FC<PaginationProps>;
176
+ interface FilterOption {
177
+ value: string;
178
+ label: string;
179
+ }
180
+ interface FilterDefinition {
181
+ /** Stable identifier; also the React key for this filter's dropdown. */
182
+ key: string;
183
+ /** Shown as the dropdown's placeholder/aria-label, and as its entry in the "Add filter" menu. */
184
+ label: string;
185
+ options: FilterOption[];
186
+ /** `null` (not `''`) represents "no selection" — the value FilterBar clears back to. */
187
+ value: string | null;
188
+ onChange: (value: string | null) => void;
189
+ /** Always rendered when true. Omit/false to make this filter addable/removable via the "Add filter" menu. */
190
+ alwaysVisible?: boolean;
191
+ }
192
+ interface FilterBarSearchProps {
193
+ value: string;
194
+ onChange: (value: string) => void;
195
+ placeholder?: string;
196
+ }
197
+ interface FilterBarProps {
198
+ filters: FilterDefinition[];
199
+ /** Renders a SearchBox ahead of the filter dropdowns when provided. */
200
+ search?: FilterBarSearchProps;
201
+ /**
202
+ * Called by "Clear all" instead of FilterBar's own clearing logic. Omit it to let FilterBar
203
+ * clear every filter with a value itself (`filter.onChange(null)` for each).
204
+ */
205
+ onClearAll?: () => void;
206
+ addFilterLabel?: string;
207
+ className?: string;
208
+ }
209
+ /**
210
+ * FilterBar — delegates to the platform's real FilterBar at render time: an optional
211
+ * SearchBox, always-visible filter dropdowns, and optional filters the user can add/remove via
212
+ * an "Add filter" menu (a filter with a non-null `value` is always treated as visible, even
213
+ * before the user explicitly adds it). The fallback renders every filter as a plain,
214
+ * always-visible native `<select>` — no add/remove menu, no styled search box — so an app page
215
+ * under test still exposes every filter's full behavior via `onChange`.
216
+ *
217
+ * @example
218
+ * <FilterBar
219
+ * search={{ value: search, onChange: setSearch, placeholder: 'Search apps…' }}
220
+ * filters={[
221
+ * { key: 'vendor', label: 'Vendor', options: vendorOptions, value: vendor, onChange: setVendor, alwaysVisible: true },
222
+ * { key: 'category', label: 'Category', options: categoryOptions, value: category, onChange: setCategory },
223
+ * ]}
224
+ * />
225
+ */
226
+ declare const FilterBar: React.FC<FilterBarProps>;
227
+ type SortDirection = 'asc' | 'desc';
228
+ interface SortOption {
229
+ value: string;
230
+ label: string;
231
+ }
232
+ interface SortSelectProps {
233
+ /** Sortable fields, e.g. `[{ value: 'name', label: 'Name' }, { value: 'updatedAt', label: 'Updated' }]`. */
234
+ options: SortOption[];
235
+ /** Selected field key. */
236
+ value: string;
237
+ direction: SortDirection;
238
+ /** Called with the field and direction together, whichever one the interaction changed. */
239
+ onChange: (value: string, direction: SortDirection) => void;
240
+ disabled?: boolean;
241
+ className?: string;
242
+ }
243
+ /**
244
+ * SortSelect — delegates to the platform's real SortSelect at render time: a labeled field
245
+ * Select paired with an asc/desc direction toggle button, styled to sit in the same toolbar
246
+ * row as FilterBar. The standalone sort control for list/card surfaces that aren't a
247
+ * DataTable (which has its own column-header sort). The fallback is a native `<select>` for
248
+ * the field plus a button that flips direction.
249
+ *
250
+ * @example
251
+ * <SortSelect
252
+ * options={[{ value: 'name', label: 'Name' }, { value: 'updatedAt', label: 'Last updated' }]}
253
+ * value={sortField}
254
+ * direction={sortDirection}
255
+ * onChange={(field, direction) => { setSortField(field); setSortDirection(direction) }}
256
+ * />
257
+ */
258
+ declare const SortSelect: React.FC<SortSelectProps>;
130
259
  interface FormFieldProps {
131
260
  label?: string;
132
261
  htmlFor?: string;
@@ -390,4 +519,4 @@ interface ConfirmationDialogContextValue {
390
519
  */
391
520
  declare function useConfirmDialog(): ConfirmationDialogContextValue;
392
521
 
393
- export { Badge, type BadgeProps, type BadgeSize, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Card, CardBody, type CardBodyProps, CardFooter, type CardFooterProps, CardHeader, type CardHeaderProps, type CardProps, Checkbox, type CheckboxProps, type ConfirmationDialogContextValue, type ConfirmationOptions, type ConfirmationVariant, DataTable, type DataTableAlign, type DataTableColumn, type DataTableEmptyState, type DataTablePaginationState, type DataTableProps, type DataTableSort, type DataTableSortOrder, EmptyState, type EmptyStateProps, FormDialog, type FormDialogProps, type FormDialogSize, FormField, type FormFieldProps, Input, type InputProps, type InputSize, type InputVariant, Select, type SelectOption, type SelectProps, type SelectSize, Skeleton, SkeletonCard, type SkeletonCardProps, type SkeletonProps, SkeletonText, type SkeletonTextProps, type SkeletonVariant, Spinner, type SpinnerProps, type SpinnerSize, StatsCard, type StatsCardDelta, type StatsCardProps, type StatsCardVariant, type TabItem, Tabs, type TabsProps, Textarea, type TextareaProps, type Toast, type ToastContextValue, type ToastOptions, type ToastVariant, Tooltip, type TooltipPlacement, type TooltipProps, useConfirmDialog, useToast };
522
+ export { Badge, type BadgeProps, type BadgeSize, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Card, CardBody, type CardBodyProps, CardFooter, type CardFooterProps, CardHeader, type CardHeaderProps, type CardProps, Checkbox, type CheckboxProps, type ConfirmationDialogContextValue, type ConfirmationOptions, type ConfirmationVariant, DataTable, type DataTableAlign, type DataTableColumn, type DataTableEmptyState, type DataTablePaginationState, type DataTableProps, type DataTableSort, type DataTableSortOrder, EmptyState, type EmptyStateProps, FilterBar, type FilterBarProps, type FilterBarSearchProps, type FilterDefinition, type FilterOption, FormDialog, type FormDialogProps, type FormDialogSize, FormField, type FormFieldProps, Input, type InputProps, type InputSize, type InputVariant, Pagination, type PaginationProps, SearchBox, type SearchBoxProps, type SearchBoxSize, Select, type SelectOption, type SelectProps, type SelectSize, Skeleton, SkeletonCard, type SkeletonCardProps, type SkeletonProps, SkeletonText, type SkeletonTextProps, type SkeletonVariant, type SortDirection, type SortOption, SortSelect, type SortSelectProps, Spinner, type SpinnerProps, type SpinnerSize, StatsCard, type StatsCardDelta, type StatsCardProps, type StatsCardVariant, type TabItem, Tabs, type TabsProps, Textarea, type TextareaProps, type Toast, type ToastContextValue, type ToastOptions, type ToastVariant, Tooltip, type TooltipPlacement, type TooltipProps, useConfirmDialog, useToast };
package/dist/ui/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getHostRuntime
3
- } from "../chunk-NY6C4REE.js";
3
+ } from "../chunk-EOOEHZGC.js";
4
4
 
5
5
  // src/ui/index.tsx
6
6
  import * as React from "react";
@@ -234,6 +234,110 @@ var Select = (props) => {
234
234
  ] });
235
235
  };
236
236
  Select.displayName = "Select";
237
+ var SearchBox = (props) => {
238
+ const HostSearchBox = getHostUi("SearchBox");
239
+ if (HostSearchBox) return /* @__PURE__ */ jsx(HostSearchBox, { ...props });
240
+ const { value, onChange, placeholder, disabled, className, "aria-label": ariaLabel } = props;
241
+ return /* @__PURE__ */ jsx(
242
+ "input",
243
+ {
244
+ type: "search",
245
+ value,
246
+ onChange: (event) => onChange(event.target.value),
247
+ placeholder,
248
+ disabled,
249
+ "aria-label": ariaLabel ?? placeholder ?? "Search",
250
+ className,
251
+ style: { ...fallbackNote, width: "100%", padding: "6px 10px", borderRadius: 6, border: "1px solid #9ca3af" }
252
+ }
253
+ );
254
+ };
255
+ SearchBox.displayName = "SearchBox";
256
+ var Pagination = (props) => {
257
+ const HostPagination = getHostUi("Pagination");
258
+ if (HostPagination) return /* @__PURE__ */ jsx(HostPagination, { ...props });
259
+ const { page, pageSize, totalItems, onPageChange, disabled, className } = props;
260
+ const pageCount = Math.max(1, Math.ceil(totalItems / pageSize));
261
+ const canGoPrev = !disabled && page > 1;
262
+ const canGoNext = !disabled && page < pageCount;
263
+ return /* @__PURE__ */ jsxs("nav", { "aria-label": "Pagination", className, style: { ...fallbackNote, display: "flex", alignItems: "center", gap: 12 }, children: [
264
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onPageChange(page - 1), disabled: !canGoPrev, style: { padding: "4px 10px" }, children: "Prev" }),
265
+ /* @__PURE__ */ jsxs("span", { children: [
266
+ "page ",
267
+ page,
268
+ " of ",
269
+ pageCount
270
+ ] }),
271
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onPageChange(page + 1), disabled: !canGoNext, style: { padding: "4px 10px" }, children: "Next" })
272
+ ] });
273
+ };
274
+ Pagination.displayName = "Pagination";
275
+ var FilterBar = (props) => {
276
+ const HostFilterBar = getHostUi("FilterBar");
277
+ if (HostFilterBar) return /* @__PURE__ */ jsx(HostFilterBar, { ...props });
278
+ const { filters, search, className } = props;
279
+ return /* @__PURE__ */ jsxs("div", { className, style: { ...fallbackNote, display: "flex", flexWrap: "wrap", gap: 8, alignItems: "center" }, children: [
280
+ search && /* @__PURE__ */ jsx(
281
+ "input",
282
+ {
283
+ type: "search",
284
+ "aria-label": search.placeholder ?? "Search",
285
+ placeholder: search.placeholder,
286
+ value: search.value,
287
+ onChange: (event) => search.onChange(event.target.value),
288
+ style: { padding: "6px 10px", borderRadius: 6, border: "1px solid #9ca3af" }
289
+ }
290
+ ),
291
+ filters.map((filter) => /* @__PURE__ */ jsxs("label", { style: { display: "flex", flexDirection: "column", fontSize: 12 }, children: [
292
+ filter.label,
293
+ /* @__PURE__ */ jsxs(
294
+ "select",
295
+ {
296
+ "aria-label": filter.label,
297
+ value: filter.value ?? "",
298
+ onChange: (event) => filter.onChange(event.target.value === "" ? null : event.target.value),
299
+ style: { padding: "6px 10px", borderRadius: 6, border: "1px solid #9ca3af" },
300
+ children: [
301
+ /* @__PURE__ */ jsx("option", { value: "", children: filter.label }),
302
+ filter.options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
303
+ ]
304
+ }
305
+ )
306
+ ] }, filter.key))
307
+ ] });
308
+ };
309
+ FilterBar.displayName = "FilterBar";
310
+ var SortSelect = (props) => {
311
+ const HostSortSelect = getHostUi("SortSelect");
312
+ if (HostSortSelect) return /* @__PURE__ */ jsx(HostSortSelect, { ...props });
313
+ const { options, value, direction, onChange, disabled, className } = props;
314
+ const directionLabel = direction === "asc" ? "Sort ascending" : "Sort descending";
315
+ return /* @__PURE__ */ jsxs("div", { className, style: { ...fallbackNote, display: "flex", alignItems: "center", gap: 6 }, children: [
316
+ /* @__PURE__ */ jsx(
317
+ "select",
318
+ {
319
+ "aria-label": "Sort by",
320
+ value,
321
+ disabled,
322
+ onChange: (event) => onChange(event.target.value, direction),
323
+ style: { padding: "6px 10px", borderRadius: 6, border: "1px solid #9ca3af" },
324
+ children: options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
325
+ }
326
+ ),
327
+ /* @__PURE__ */ jsx(
328
+ "button",
329
+ {
330
+ type: "button",
331
+ disabled,
332
+ onClick: () => onChange(value, direction === "asc" ? "desc" : "asc"),
333
+ "aria-label": directionLabel,
334
+ style: { padding: "4px 10px" },
335
+ children: direction === "asc" ? "\u2191" : "\u2193"
336
+ }
337
+ )
338
+ ] });
339
+ };
340
+ SortSelect.displayName = "SortSelect";
237
341
  var FormField = (props) => {
238
342
  const HostFormField = getHostUi("FormField");
239
343
  if (HostFormField) return /* @__PURE__ */ jsx(HostFormField, { ...props });
@@ -582,13 +686,17 @@ export {
582
686
  Checkbox,
583
687
  DataTable,
584
688
  EmptyState,
689
+ FilterBar,
585
690
  FormDialog,
586
691
  FormField,
587
692
  Input,
693
+ Pagination,
694
+ SearchBox,
588
695
  Select,
589
696
  Skeleton,
590
697
  SkeletonCard,
591
698
  SkeletonText,
699
+ SortSelect,
592
700
  Spinner,
593
701
  StatsCard,
594
702
  Tabs,