@lobb-js/studio 0.35.0 → 0.36.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.
@@ -86,7 +86,23 @@
86
86
  });
87
87
  }
88
88
 
89
- function detectAndParse(content: string): any[] {
89
+ async function detectAndParse(content: string): Promise<any[]> {
90
+ // Give projects a chance to take over parsing for non-standard
91
+ // formats (preamble rows, multi-line cells, vendor exports, …) by
92
+ // registering a workflow on `studio.collections.import.parse`. The
93
+ // workflow receives the raw text and sets `handled: true` along
94
+ // with its own `rows`; if no workflow takes over, we fall through
95
+ // to the built-in JSON / simple-CSV detector.
96
+ const result = await emitEvent({ lobb, ctx }, "studio.collections.import.parse", {
97
+ collectionName,
98
+ content,
99
+ rows: null as any[] | null,
100
+ handled: false,
101
+ });
102
+ if (result?.handled && Array.isArray(result.rows)) {
103
+ return result.rows;
104
+ }
105
+
90
106
  const trimmed = content.trim();
91
107
  if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
92
108
  const parsed = JSON.parse(trimmed);
@@ -98,7 +114,7 @@
98
114
  async function processContent(content: string) {
99
115
  parseError = "";
100
116
  try {
101
- const rows = detectAndParse(content);
117
+ const rows = await detectAndParse(content);
102
118
  if (rows.length === 0) throw new Error("No data rows found");
103
119
  transformedRows = applyColumnMapping(rows);
104
120
  step = "preview";
@@ -2,5 +2,5 @@ import { Accordion as AccordionPrimitive } from "bits-ui";
2
2
  import Content from "./accordion-content.svelte";
3
3
  import Item from "./accordion-item.svelte";
4
4
  import Trigger from "./accordion-trigger.svelte";
5
- declare const Root: import("svelte").Component<AccordionPrimitive.RootProps, {}, "ref" | "value">;
5
+ declare const Root: import("svelte").Component<AccordionPrimitive.RootProps, {}, "value" | "ref">;
6
6
  export { Root, Content, Item, Trigger, Root as Accordion, Content as AccordionContent, Item as AccordionItem, Trigger as AccordionTrigger, };
@@ -4,6 +4,6 @@ type $$ComponentProps = WithoutChildrenOrChild<DialogPrimitive.RootProps> & With
4
4
  portalProps?: DialogPrimitive.PortalProps;
5
5
  children: Snippet;
6
6
  };
7
- declare const CommandDialog: import("svelte").Component<$$ComponentProps, {}, "ref" | "value" | "open">;
7
+ declare const CommandDialog: import("svelte").Component<$$ComponentProps, {}, "value" | "ref" | "open">;
8
8
  type CommandDialog = ReturnType<typeof CommandDialog>;
9
9
  export default CommandDialog;
@@ -1,4 +1,4 @@
1
1
  import { Command as CommandPrimitive } from "bits-ui";
2
- declare const CommandInput: import("svelte").Component<CommandPrimitive.InputProps, {}, "ref" | "value">;
2
+ declare const CommandInput: import("svelte").Component<CommandPrimitive.InputProps, {}, "value" | "ref">;
3
3
  type CommandInput = ReturnType<typeof CommandInput>;
4
4
  export default CommandInput;
@@ -1,4 +1,4 @@
1
1
  import { Command as CommandPrimitive } from "bits-ui";
2
- declare const Command: import("svelte").Component<CommandPrimitive.RootProps, {}, "ref" | "value">;
2
+ declare const Command: import("svelte").Component<CommandPrimitive.RootProps, {}, "value" | "ref">;
3
3
  type Command = ReturnType<typeof Command>;
4
4
  export default Command;
@@ -8,6 +8,6 @@ type Props = WithElementRef<Omit<HTMLInputAttributes, "type"> & ({
8
8
  type?: InputType;
9
9
  files?: undefined;
10
10
  })>;
11
- declare const Input: import("svelte").Component<Props, {}, "ref" | "value" | "files">;
11
+ declare const Input: import("svelte").Component<Props, {}, "value" | "ref" | "files">;
12
12
  type Input = ReturnType<typeof Input>;
13
13
  export default Input;
@@ -1,5 +1,5 @@
1
1
  import { RangeCalendar as RangeCalendarPrimitive } from "bits-ui";
2
2
  import * as RangeCalendar from "./index.js";
3
- declare const RangeCalendar: import("svelte").Component<Omit<Omit<RangeCalendarPrimitive.RootProps, "child">, "children">, {}, "placeholder" | "ref" | "value">;
3
+ declare const RangeCalendar: import("svelte").Component<Omit<Omit<RangeCalendarPrimitive.RootProps, "child">, "children">, {}, "value" | "ref" | "placeholder">;
4
4
  type RangeCalendar = ReturnType<typeof RangeCalendar>;
5
5
  export default RangeCalendar;
@@ -1,5 +1,5 @@
1
1
  import type { WithElementRef } from "bits-ui";
2
2
  import type { HTMLTextareaAttributes } from "svelte/elements";
3
- declare const Textarea: import("svelte").Component<Omit<WithElementRef<HTMLTextareaAttributes>, "children">, {}, "ref" | "value">;
3
+ declare const Textarea: import("svelte").Component<Omit<WithElementRef<HTMLTextareaAttributes>, "children">, {}, "value" | "ref">;
4
4
  type Textarea = ReturnType<typeof Textarea>;
5
5
  export default Textarea;
@@ -69,6 +69,12 @@ export interface ExtensionUtils {
69
69
  openDataTableDrawer: (props: OpenDataTableDrawerProps) => void;
70
70
  openDataTablePopup: (props: OpenDataTablePopupProps) => void;
71
71
  emitEvent: (eventName: string, input: any) => Promise<any>;
72
+ /**
73
+ * Shorthand for the standalone `isHidden(ctx, id)` helper — returns
74
+ * true when the project has opted to hide the UI element registered
75
+ * under the given identifier in its `ui.hide` config.
76
+ */
77
+ isHidden: (id: string) => boolean;
72
78
  components: Components;
73
79
  mediaQueries: typeof mediaQueries;
74
80
  intlDate: typeof intlDate;
@@ -60,6 +60,7 @@ export function getExtensionUtils(lobb, ctx) {
60
60
  openDataTableDrawer: (props) => openDataTableDrawer({ lobb, ctx }, props),
61
61
  openDataTablePopup: (props) => openDataTablePopup({ lobb, ctx }, props),
62
62
  emitEvent: (eventName, input) => emitEvent({ lobb, ctx }, eventName, input),
63
+ isHidden: (id) => ctx.meta?.ui?.hide?.[id] === true,
63
64
  components: getComponents(),
64
65
  mediaQueries: mediaQueries,
65
66
  intlDate: intlDate,
package/dist/index.d.ts CHANGED
@@ -26,3 +26,4 @@ export { default as DataTable } from "./components/dataTable/dataTable.svelte";
26
26
  export { default as Drawer } from "./components/drawer.svelte";
27
27
  export { default as SelectRecord } from "./components/selectRecord.svelte";
28
28
  export { Switch } from "./components/ui/switch";
29
+ export { isHidden } from "./utils";
package/dist/index.js CHANGED
@@ -25,3 +25,4 @@ export { default as DataTable } from "./components/dataTable/dataTable.svelte";
25
25
  export { default as Drawer } from "./components/drawer.svelte";
26
26
  export { default as SelectRecord } from "./components/selectRecord.svelte";
27
27
  export { Switch } from "./components/ui/switch";
28
+ export { isHidden } from "./utils";
@@ -1,4 +1,6 @@
1
1
  import type { Extension } from "./extensions/extension.types";
2
+ import type { UIConfig, UITheme } from "@lobb-js/core";
3
+ export type { UITheme };
2
4
  export interface CollectionTab {
3
5
  id?: string;
4
6
  label: string;
@@ -30,16 +32,9 @@ interface Collection {
30
32
  };
31
33
  }
32
34
  type Collections = Record<string, Collection>;
33
- export interface UITheme {
34
- light?: Record<string, string>;
35
- dark?: Record<string, string>;
36
- }
37
35
  interface Meta {
38
36
  version: string;
39
- ui?: {
40
- theme?: UITheme;
41
- horizontalNav?: boolean;
42
- };
37
+ ui?: UIConfig;
43
38
  relations: Array<any>;
44
39
  collections: Collections;
45
40
  extensions: Record<string, any>;
@@ -54,4 +49,3 @@ export interface CTX {
54
49
  meta: Meta;
55
50
  currentUrl: URL;
56
51
  }
57
- export {};
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type ClassValue } from "clsx";
2
2
  import { MediaQuery } from 'svelte/reactivity';
3
+ import type { CTX } from "./store.types";
3
4
  export declare function cn(...inputs: ClassValue[]): string;
4
5
  export type WithoutChild<T> = T extends {
5
6
  child?: any;
@@ -19,6 +20,7 @@ export declare const mediaQueries: {
19
20
  '2xl': MediaQuery;
20
21
  };
21
22
  export declare function getFieldTypeLabel(type: string | undefined | null): string;
23
+ export declare function isHidden(ctx: CTX | null | undefined, id: string): boolean;
22
24
  export declare function calculateDrawerWidth(): number;
23
25
  export declare function getChangedProperties(oldObj: Record<string, any>, newObj: Record<string, any>): Record<string, any>;
24
26
  export declare function parseFunction(functionString: string): any;
package/dist/utils.js CHANGED
@@ -24,6 +24,14 @@ export function getFieldTypeLabel(type) {
24
24
  return "";
25
25
  return FIELD_TYPE_LABELS[type] ?? type;
26
26
  }
27
+ // Settings-based visibility check. Returns true when the project has
28
+ // opted to hide the UI element registered under the given identifier
29
+ // in its `ui.hide` config (e.g. "reports.dashboardShareButton").
30
+ // Components that support hiding wrap their render with
31
+ // `{#if !isHidden(ctx, "...")}`.
32
+ export function isHidden(ctx, id) {
33
+ return ctx?.meta?.ui?.hide?.[id] === true;
34
+ }
27
35
  export function calculateDrawerWidth() {
28
36
  const backgroundDrawerButtons = document.querySelectorAll(".backgroundDrawerButton");
29
37
  const drawersCount = Array.from(backgroundDrawerButtons).length;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lobb-js/studio",
3
3
  "license": "UNLICENSED",
4
- "version": "0.35.0",
4
+ "version": "0.36.0",
5
5
  "type": "module",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -42,7 +42,7 @@
42
42
  "postpublish": "./scripts/postpublish.sh"
43
43
  },
44
44
  "devDependencies": {
45
- "@lobb-js/core": "^0.35.0",
45
+ "@lobb-js/core": "^0.36.0",
46
46
  "@chromatic-com/storybook": "^4.1.2",
47
47
  "@storybook/addon-a11y": "^10.0.1",
48
48
  "@storybook/addon-docs": "^10.0.1",
@@ -86,7 +86,23 @@
86
86
  });
87
87
  }
88
88
 
89
- function detectAndParse(content: string): any[] {
89
+ async function detectAndParse(content: string): Promise<any[]> {
90
+ // Give projects a chance to take over parsing for non-standard
91
+ // formats (preamble rows, multi-line cells, vendor exports, …) by
92
+ // registering a workflow on `studio.collections.import.parse`. The
93
+ // workflow receives the raw text and sets `handled: true` along
94
+ // with its own `rows`; if no workflow takes over, we fall through
95
+ // to the built-in JSON / simple-CSV detector.
96
+ const result = await emitEvent({ lobb, ctx }, "studio.collections.import.parse", {
97
+ collectionName,
98
+ content,
99
+ rows: null as any[] | null,
100
+ handled: false,
101
+ });
102
+ if (result?.handled && Array.isArray(result.rows)) {
103
+ return result.rows;
104
+ }
105
+
90
106
  const trimmed = content.trim();
91
107
  if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
92
108
  const parsed = JSON.parse(trimmed);
@@ -98,7 +114,7 @@
98
114
  async function processContent(content: string) {
99
115
  parseError = "";
100
116
  try {
101
- const rows = detectAndParse(content);
117
+ const rows = await detectAndParse(content);
102
118
  if (rows.length === 0) throw new Error("No data rows found");
103
119
  transformedRows = applyColumnMapping(rows);
104
120
  step = "preview";
@@ -73,6 +73,12 @@ export interface ExtensionUtils {
73
73
  openDataTableDrawer: (props: OpenDataTableDrawerProps) => void;
74
74
  openDataTablePopup: (props: OpenDataTablePopupProps) => void;
75
75
  emitEvent: (eventName: string, input: any) => Promise<any>;
76
+ /**
77
+ * Shorthand for the standalone `isHidden(ctx, id)` helper — returns
78
+ * true when the project has opted to hide the UI element registered
79
+ * under the given identifier in its `ui.hide` config.
80
+ */
81
+ isHidden: (id: string) => boolean;
76
82
  components: Components;
77
83
  mediaQueries: typeof mediaQueries;
78
84
  intlDate: typeof intlDate;
@@ -70,6 +70,7 @@ export function getExtensionUtils(lobb: LobbClient, ctx: CTX): ExtensionUtils {
70
70
  openDataTableDrawer: (props) => openDataTableDrawer({ lobb, ctx }, props),
71
71
  openDataTablePopup: (props) => openDataTablePopup({ lobb, ctx }, props),
72
72
  emitEvent: (eventName, input) => emitEvent({ lobb, ctx }, eventName, input),
73
+ isHidden: (id) => ctx.meta?.ui?.hide?.[id] === true,
73
74
  components: getComponents(),
74
75
  mediaQueries: mediaQueries,
75
76
  intlDate: intlDate,
package/src/lib/index.ts CHANGED
@@ -26,4 +26,5 @@ export { default as RangeCalendarButton } from "./components/rangeCalendarButton
26
26
  export { default as DataTable } from "./components/dataTable/dataTable.svelte";
27
27
  export { default as Drawer } from "./components/drawer.svelte";
28
28
  export { default as SelectRecord } from "./components/selectRecord.svelte";
29
- export { Switch } from "./components/ui/switch";
29
+ export { Switch } from "./components/ui/switch";
30
+ export { isHidden } from "./utils";
@@ -1,4 +1,9 @@
1
1
  import type { Extension } from "./extensions/extension.types";
2
+ import type { UIConfig, UITheme } from "@lobb-js/core";
3
+
4
+ // Re-export so existing imports of UITheme from the studio package
5
+ // keep working without touching every consumer.
6
+ export type { UITheme };
2
7
 
3
8
  export interface CollectionTab {
4
9
  id?: string;
@@ -27,14 +32,9 @@ interface Collection {
27
32
  }
28
33
  type Collections = Record<string, Collection>;
29
34
 
30
- export interface UITheme {
31
- light?: Record<string, string>;
32
- dark?: Record<string, string>;
33
- }
34
-
35
35
  interface Meta {
36
36
  version: string;
37
- ui?: { theme?: UITheme; horizontalNav?: boolean };
37
+ ui?: UIConfig;
38
38
  relations: Array<any>;
39
39
  collections: Collections;
40
40
  extensions: Record<string, any>;
package/src/lib/utils.ts CHANGED
@@ -3,6 +3,7 @@ import { twMerge } from "tailwind-merge";
3
3
  import { isEqual } from "lodash-es";
4
4
 
5
5
  import { MediaQuery } from 'svelte/reactivity';
6
+ import type { CTX } from "./store.types";
6
7
 
7
8
  export function cn(...inputs: ClassValue[]) {
8
9
  return twMerge(clsx(inputs));
@@ -36,6 +37,15 @@ export function getFieldTypeLabel(type: string | undefined | null): string {
36
37
  return FIELD_TYPE_LABELS[type] ?? type;
37
38
  }
38
39
 
40
+ // Settings-based visibility check. Returns true when the project has
41
+ // opted to hide the UI element registered under the given identifier
42
+ // in its `ui.hide` config (e.g. "reports.dashboardShareButton").
43
+ // Components that support hiding wrap their render with
44
+ // `{#if !isHidden(ctx, "...")}`.
45
+ export function isHidden(ctx: CTX | null | undefined, id: string): boolean {
46
+ return ctx?.meta?.ui?.hide?.[id] === true;
47
+ }
48
+
39
49
 
40
50
  export function calculateDrawerWidth() {
41
51
  const backgroundDrawerButtons = document.querySelectorAll(".backgroundDrawerButton");