@superblocksteam/cli 2.0.3-next.217 → 2.0.3-next.219

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/README.md CHANGED
@@ -14,7 +14,7 @@ $ npm install -g @superblocksteam/cli
14
14
  $ superblocks COMMAND
15
15
  running command...
16
16
  $ superblocks (--version)
17
- @superblocksteam/cli/2.0.3-next.217 linux-x64 node-v20.19.0
17
+ @superblocksteam/cli/2.0.3-next.219 linux-x64 node-v20.19.0
18
18
  $ superblocks --help [COMMAND]
19
19
  USAGE
20
20
  $ superblocks COMMAND
@@ -48,11 +48,11 @@ var content5 = "# Data Filtering Best Practices\n\n**\u{1F6A8} CRITICAL: When im
48
48
 
49
49
  // ../../../vite-plugin-file-sync/dist/ai-service/prompts/generated/subprompts/superblocks-event-flow.js
50
50
  init_cjs_shims();
51
- var content6 = '# Event handlers with SbEventFlow\n\nRather than using standard browser event handlers, Superblocks provides a structured event handler action flow that allows you to run a series of events within the Superblocks system.\n\nImporting SbEventFlow:\n\n```jsx\nimport { SbEventFlow } from "@superblocksteam/library";\n```\n\nAll event handlers MUST be written using the `SbEventFlow` object.\n\nFor example, here we set the `isReady` state variable to `true` when the button is clicked:\n\n```jsx\nconst { isReady } = Page1;\n<SbButton onClick={SbEventFlow.setStateVar(isReady, true)} />;\n```\n\n## SbEventFlow builder pattern\n\n`SbEventFlow` provides a number of functions that can be chained together using `SbEventFlow` which correspond to actions in the Superblocks system.\n\nYou should always use these dedicated functions for individual and sequential actions.\n\nImportant: DO NOT use .run() at the end of a chain of SbEventFlow functions, it is not needed and it will throw an error.\n\n```jsx\nconst { isReady, getUserData, getPermissions } = Page1;\n<SbButton\n onClick={SbEventFlow.setQueryParams({ filter: "active" }, true)\n .setStateVar(isReady, true)\n .controlModal("loginModal", "close")\n\n // run APIs allows you to run Superblocks APIs by name using string arrays\n // Each runAPIs call executes the list of API names supplied in parallel\n .runApis([getUserData, getPermissions])\n\n // set a state variable\'s value\n .showAlert("Workflow complete", "success")\n .navigateTo({ url: "/dashboard", newWindow: false })}\n/>;\n```\n\n#### Using RunJS (only when needed)\n\n`SbEventFlow` also has a special `runJS` event type that allows you to run any JavaScript in the browser.\n\nThis allows you to write more complex logic such as control flow.\n\nImportant:\n\n- The only things you can do in runJS is set state variables or set the public state of components, like modal.isOpen.\n- You CANNOT use SbEventFlow inside of a SbEventFlow.runJS function. If you do this, it won\'t work!\n- **State access in runJS**: Scope entities are accessible directly by their names, global state is accessible via imported globals (Global, Theme, Embed, Env).\n\nExample accessing scope entities:\n\n```jsx\n<SbButton\n label="Enable"\n buttonStyle={"SECONDARY_BUTTON"}\n onClick={SbEventFlow.runJS(() => {\n // Scope entities (variables, bound components) are accessible directly in runJS\n if (isUserAdmin.value) {\n // isUserAdmin is a bound component from scope\n myStateVar.value = true; // myStateVar is a state variable from scope\n myModal.isOpen = false; // myModal is a bound component from scope\n } else {\n console.log("This user was not an admin");\n }\n })}\n/>\n```\n\nExample accessing global state when needed:\n\n```jsx\n<SbButton\n label="Personalized Action"\n onClick={SbEventFlow.runJS(() => {\n // Import globals and access directly\n if (Global.user.groups.some((g) => g.name === "admin")) {\n // Also access scope entities (bound components) directly\n adminPanel.isVisible = true; // adminPanel is a bound component from scope\n }\n console.log(`Welcome ${Global.user.name}!`);\n })}\n/>\n```\n\nAs mentioned above, you should only use `runJS` when the flow is too complex to represent using only chained event flow actions.\n\n### SbEvent Flow Usage Examples\n\n```typescript\nimport { SbEventFlow, sbComputed } from "@superblocksteam/library";\nimport { Page1 } from "./scope";\n\nconst { fetchUserData, saveUserData, userDataVariable } = Page1;\n\n// Navigation example\nSbEventFlow.navigateTo({ url: "https://example.com", newWindow: true });\n\n// Control UI components example\nSbEventFlow.controlModal("myModal", "open");\n\n// State management example\nconst { userProfile } = Page1;\nSbEventFlow.setStateVar(userProfile, { name: "John", role: "Admin" });\n\n// Chaining multiple actions\nSbEventFlow.runApis([fetchUserData])\n .setStateVar(\n userDataVariable,\n sbComputed(() => {\n fetchUserData.response;\n }),\n )\n .showAlert("Data loaded successfully", "success");\n\n// Conditional flow with success/error handlers\nconst successFlow = SbEventFlow.showAlert("Success!", "success");\nconst errorFlow = SbEventFlow.showAlert("An error occurred", "error");\nSbEventFlow.runApis([saveUserData], successFlow, errorFlow);\n```\n\n**SbEventFlow: Managing Events and Side Effects in Superblocks**\n\n## Important Syntax Rules\n\n- Always use function braces with SbEventFlow.runJS. Example: `SbEventFlow.runJS(() => { someFunction(); })` not `SbEventFlow.runJS(() => someFunction())`\n- SbEventFlow.runApis() accepts an array of direct API entity references. Example: `SbEventFlow.runApis([fetchUserData, saveUserData])`\n';
51
+ var content6 = '# Event handlers with SbEventFlow\n\nRather than using standard browser event handlers, Superblocks provides a structured event handler action flow that allows you to run a series of events within the Superblocks system.\n\nImporting SbEventFlow:\n\n```jsx\nimport { SbEventFlow } from "@superblocksteam/library";\n```\n\nAll event handlers MUST be written using the `SbEventFlow` object.\n\nFor example, here we set the `isReady` state variable to `true` when the button is clicked:\n\n```jsx\nconst { isReady } = Page1;\n<SbButton onClick={SbEventFlow.setStateVar(isReady, true)} />;\n```\n\n## SbEventFlow builder pattern\n\n`SbEventFlow` provides a number of functions that can be chained together using `SbEventFlow` which correspond to actions in the Superblocks system.\n\nYou should always use these dedicated functions for individual and sequential actions.\n\nImportant: DO NOT use .run() at the end of a chain of SbEventFlow functions, it is not needed and it will throw an error.\n\n```jsx\nconst { isReady, getUserData, getPermissions, LoginModal } = Page1;\n<SbButton\n onClick={SbEventFlow.setQueryParams({ filter: "active" }, true)\n .setStateVar(isReady, true)\n .controlModal(LoginModal, "close")\n\n // run APIs allows you to run Superblocks APIs by name using string arrays\n // Each runAPIs call executes the list of API names supplied in parallel\n .runApis([getUserData, getPermissions])\n\n // set a state variable\'s value\n .showAlert("Workflow complete", "success")\n .navigateTo({ url: "/dashboard", newWindow: false })}\n/>;\n```\n\n#### Using RunJS (only when needed)\n\n`SbEventFlow` also has a special `runJS` event type that allows you to run any JavaScript in the browser.\n\nThis allows you to write more complex logic such as control flow.\n\nImportant:\n\n- The only things you can do in runJS is set state variables or set the public state of components, like modal.isOpen.\n- You CANNOT use SbEventFlow inside of a SbEventFlow.runJS function. If you do this, it won\'t work!\n- **State access in runJS**: Scope entities are accessible directly by their names, global state is accessible via imported globals (Global, Theme, Embed, Env).\n\nExample accessing scope entities:\n\n```jsx\n<SbButton\n label="Enable"\n buttonStyle={"SECONDARY_BUTTON"}\n onClick={SbEventFlow.runJS(() => {\n // Scope entities (variables, bound components) are accessible directly in runJS\n if (isUserAdmin.value) {\n // isUserAdmin is a bound component from scope\n myStateVar.value = true; // myStateVar is a state variable from scope\n myModal.isOpen = false; // myModal is a bound component from scope\n } else {\n console.log("This user was not an admin");\n }\n })}\n/>\n```\n\nExample accessing global state when needed:\n\n```jsx\n<SbButton\n label="Personalized Action"\n onClick={SbEventFlow.runJS(() => {\n // Import globals and access directly\n if (Global.user.groups.some((g) => g.name === "admin")) {\n // Also access scope entities (bound components) directly\n adminPanel.isVisible = true; // adminPanel is a bound component from scope\n }\n console.log(`Welcome ${Global.user.name}!`);\n })}\n/>\n```\n\nAs mentioned above, you should only use `runJS` when the flow is too complex to represent using only chained event flow actions.\n\n### SbEvent Flow Usage Examples\n\n```typescript\nimport { SbEventFlow, sbComputed } from "@superblocksteam/library";\nimport { Page1 } from "./scope";\n\nconst { fetchUserData, saveUserData, userDataVariable, MyModal } = Page1;\n\n// Navigation example\nSbEventFlow.navigateTo({ url: "https://example.com", newWindow: true });\n\n// Control UI components example\nSbEventFlow.controlModal(MyModal, "open");\n\n// State management example\nconst { userProfile } = Page1;\nSbEventFlow.setStateVar(userProfile, { name: "John", role: "Admin" });\n\n// Chaining multiple actions\nSbEventFlow.runApis([fetchUserData])\n .setStateVar(\n userDataVariable,\n sbComputed(() => {\n fetchUserData.response;\n }),\n )\n .showAlert("Data loaded successfully", "success");\n\n// Conditional flow with success/error handlers\nconst successFlow = SbEventFlow.showAlert("Success!", "success");\nconst errorFlow = SbEventFlow.showAlert("An error occurred", "error");\nSbEventFlow.runApis([saveUserData], successFlow, errorFlow);\n```\n\n**SbEventFlow: Managing Events and Side Effects in Superblocks**\n\n## Important Syntax Rules\n\n- Always use function braces with SbEventFlow.runJS. Example: `SbEventFlow.runJS(() => { someFunction(); })` not `SbEventFlow.runJS(() => someFunction())`\n- SbEventFlow.runApis() accepts an array of direct API entity references. Example: `SbEventFlow.runApis([fetchUserData, saveUserData])`\n';
52
52
 
53
53
  // ../../../vite-plugin-file-sync/dist/ai-service/prompts/generated/subprompts/superblocks-forms.js
54
54
  init_cjs_shims();
55
- var content7 = '### Form Layouts in Superblocks\n\n**\u{1F6A8} CRITICAL: Remember that sbComputed cannot be used as React children.** When building forms, all dynamic content must be in component properties (like `text={}`, `label={}`) not as children.\n\nWhen creating forms using form field components, follow these rules:\n\n1. Always put form components together inside an `SbContainer` with `layout="vertical"`, `width={Dim.fill()}`, and appropriate `spacing`\n2. Use `spacing={Dim.px(12)}` or similar for consistent form field spacing\n3. Do not change the label position on form components (like `SbInput`). The default is the label is above the input and we want to keep that\n4. Make all form field components and any container parents be `width={Dim.fill()}` so they are all aligned horizontally and easy to use\n\n**Example:**\n\n```jsx\n<SbContainer layout="vertical" width={Dim.fill()} spacing={Dim.px(12)}>\n <SbInput label="First Name" bind={FirstName} width={Dim.fill()} />\n <SbInput label="Last Name" bind={LastName} width={Dim.fill()} />\n <SbInput label="Email" bind={Email} inputType="EMAIL" width={Dim.fill()} />\n</SbContainer>\n```\n\n### Forms inside Modals\n\nIt\'s common to put a form inside a Modal, like for creating or editing an entity. Here are comprehensive examples showing different patterns:\n\n#### Basic Create Form Modal\n\n```tsx\n// Import required components and utilities\nimport {\n SbModal,\n SbContainer,\n SbText,\n SbInput,\n SbDropdown,\n SbButton,\n Dim,\n SbEventFlow,\n} from "@superblocksteam/library";\nimport { Page1 } from "./scope";\n\n// ...\n\nconst {\n NewOrderCustomerName,\n NewOrderCustomerEmail,\n NewOrderAmount,\n NewOrderStatus,\n NewOrderNotes,\n OrdersStateVar,\n CreateOrderModal,\n} = Page1;\n\n<SbModal bind={CreateOrderModal}>\n <SbContainer layout="vertical" width={Dim.fill()} spacing={Dim.px(24)}>\n {/* Modal Header */}\n <SbContainer layout="vertical" spacing={Dim.px(8)}>\n <SbText\n text="Create New Order"\n textStyle={{\n variant: "heading4",\n }}\n />\n <SbText text="Fill out the form below to create a new order" />\n </SbContainer>\n\n {/* Form Content */}\n <SbContainer layout="vertical" width={Dim.fill()} spacing={Dim.px(12)}>\n <SbInput\n bind={NewOrderCustomerName}\n width={Dim.fill()}\n label="Customer Name"\n placeholderText="Enter customer name"\n required={true}\n />\n\n <SbInput\n bind={NewOrderCustomerEmail}\n width={Dim.fill()}\n label="Customer Email"\n inputType="EMAIL"\n placeholderText="Enter customer email"\n required={true}\n />\n\n <SbInput\n bind={NewOrderAmount}\n width={Dim.fill()}\n label="Order Amount"\n placeholderText="Enter order amount"\n inputType="NUMBER"\n required={true}\n />\n\n <SbDropdown\n bind={NewOrderStatus}\n width={Dim.fill()}\n label="Order Status"\n options={[\n {\n label: "Pending",\n value: "pending",\n },\n {\n label: "Processing",\n value: "processing",\n },\n {\n label: "En route",\n value: "en_route",\n },\n {\n label: "Delivered",\n value: "delivered",\n },\n {\n label: "Refunded",\n value: "refunded",\n },\n ]}\n required={true}\n />\n\n <SbInput\n bind={NewOrderNotes}\n width={Dim.fill()}\n label="Order Notes"\n placeholderText="Optional notes about the order"\n multiline={true}\n />\n </SbContainer>\n\n {/* Modal Footer */}\n <SbContainer\n layout="horizontal"\n horizontalAlign="right"\n spacing={Dim.px(12)}\n width={Dim.fill()}\n >\n <SbButton\n label="Cancel"\n variant="secondary"\n onClick={SbEventFlow.runJS(() => {\n // Reset form components\n NewOrderCustomerName.text = "";\n NewOrderCustomerEmail.text = "";\n NewOrderAmount.text = "";\n NewOrderStatus.metaSelectedOptionValue = "";\n NewOrderNotes.text = "";\n })\n // Note how we prefer use controlModal for handling opening/closing\n // the modal rather than setting the modal\'s open property directly\n .controlModal("CreateOrderModal", "close")}\n />\n <SbButton\n label="Create Order"\n variant="primary"\n onClick={SbEventFlow.runJS(() => {\n // Create new order using the form values\n const newOrder = {\n id: `ORD_${Math.floor(Math.random() * 10000)\n .toString()\n .padStart(4, "0")}`,\n customerName: NewOrderCustomerName.value,\n customerEmail: NewOrderCustomerEmail.value,\n amount: NewOrderAmount.value,\n status: NewOrderStatus.selectedOptionValue,\n notes: NewOrderNotes.value,\n createdAt: new Date().toISOString(),\n };\n\n // Add to orders list or call API\n OrdersStateVar.setValue([...OrdersStateVar.value, newOrder]);\n\n // Reset form components\n NewOrderCustomerName.text = "";\n NewOrderCustomerEmail.text = "";\n NewOrderAmount.text = "";\n NewOrderStatus.metaSelectedOptionValue = "";\n NewOrderNotes.text = "";\n })\n // Note how we prefer use controlModal for handling opening/closing\n // the modal rather than setting the modal\'s open property directly\n .controlModal("CreateOrderModal", "close")}\n />\n </SbContainer>\n </SbContainer>\n</SbModal>;\n```\n\n#### Table with Edit Form Modal\n\nThis example shows a more complete pattern where a table displays data and clicking a row opens an edit modal with the form fields pre-populated:\n\n```tsx\n// Import required components and utilities\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbTable,\n SbModal,\n SbContainer,\n SbText,\n SbInput,\n SbDropdown,\n SbButton,\n Dim,\n SbEventFlow,\n sbComputed,\n} from "@superblocksteam/library";\nimport { Page1 } from "./scope";\n\nconst {\n OrdersTable,\n EditOrderModal,\n EditOrderCustomerName,\n EditOrderCustomerEmail,\n EditOrderAmount,\n EditOrderStatus,\n EditOrderNotes,\n OrdersStateVar,\n} = Page1;\n\n// Main page with table\n<SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()} spacing={Dim.px(24)}>\n <SbText\n text="Orders Management"\n textStyle={{ variant: "heading2" }}\n />\n\n <SbTable\n bind={OrdersTable}\n tableData={sbComputed(() => OrdersStateVar.value)}\n onRowClick={SbEventFlow.runJS(() => {\n // Populate form fields with the selected row data\n EditOrderCustomerName.text = OrdersTable.selectedRow.customerName;\n EditOrderCustomerEmail.text = OrdersTable.selectedRow.customerEmail;\n EditOrderAmount.text = OrdersTable.selectedRow.amount;\n EditOrderStatus.metaSelectedOptionValue = OrdersTable.selectedRow.status;\n EditOrderNotes.text = OrdersTable.selectedRow.notes || "";\n })\n // Open the edit modal\n .controlModal("EditOrderModal", "open")}\n width={Dim.fill()}\n height={Dim.fill()}\n />\n </SbColumn>\n </SbSection>\n</SbPage>\n\n// Edit modal with form pre-populated from table row\n<SbModal bind={EditOrderModal}>\n <SbContainer layout="vertical" width={Dim.fill()} spacing={Dim.px(24)}>\n {/* Modal Header */}\n <SbContainer layout="vertical" spacing={Dim.px(8)}>\n <SbText\n text="Edit Order"\n textStyle={{\n variant: "heading4",\n }}\n />\n <SbText text="Update the order details below" />\n </SbContainer>\n\n {/* Form Content - Fields are pre-populated by onRowClick */}\n <SbContainer layout="vertical" width={Dim.fill()} spacing={Dim.px(12)}>\n <SbInput\n bind={EditOrderCustomerName}\n width={Dim.fill()}\n label="Customer Name"\n placeholderText="Enter customer name"\n required={true}\n />\n\n <SbInput\n bind={EditOrderCustomerEmail}\n width={Dim.fill()}\n label="Customer Email"\n inputType="EMAIL"\n placeholderText="Enter customer email"\n required={true}\n />\n\n <SbInput\n bind={EditOrderAmount}\n width={Dim.fill()}\n label="Order Amount"\n placeholderText="Enter order amount"\n inputType="NUMBER"\n required={true}\n />\n\n <SbDropdown\n bind={EditOrderStatus}\n width={Dim.fill()}\n label="Order Status"\n options={[\n {\n label: "Pending",\n value: "pending",\n },\n {\n label: "Processing",\n value: "processing",\n },\n {\n label: "En route",\n value: "en_route",\n },\n {\n label: "Delivered",\n value: "delivered",\n },\n {\n label: "Refunded",\n value: "refunded",\n },\n ]}\n required={true}\n />\n\n <SbInput\n bind={EditOrderNotes}\n width={Dim.fill()}\n label="Order Notes"\n placeholderText="Optional notes about the order"\n multiline={true}\n />\n </SbContainer>\n\n {/* Modal Footer */}\n <SbContainer\n layout="horizontal"\n horizontalAlign="right"\n spacing={Dim.px(12)}\n width={Dim.fill()}\n >\n <SbButton\n label="Cancel"\n variant="secondary"\n onClick={SbEventFlow.controlModal("EditOrderModal", "close")}\n />\n <SbButton\n label="Save Changes"\n variant="primary"\n onClick={SbEventFlow.runJS(() => {\n // Find and update the order in the orders array\n const updatedOrders = OrdersStateVar.value.map(order => {\n if (order.id === OrdersTable.selectedRow.id) {\n return {\n ...order,\n customerName: EditOrderCustomerName.value,\n customerEmail: EditOrderCustomerEmail.value,\n amount: EditOrderAmount.value,\n status: EditOrderStatus.selectedOptionValue,\n notes: EditOrderNotes.value,\n updatedAt: new Date().toISOString(),\n };\n }\n return order;\n });\n\n // Update the orders state\n OrdersStateVar.setValue(updatedOrders);\n })\n .controlModal("EditOrderModal", "close")}\n />\n </SbContainer>\n </SbContainer>\n</SbModal>\n```\n\n**Corresponding scope.ts file for the table + edit modal example:**\n\n```ts\n// pages/Page1/scope.ts\nimport {\n createSbScope,\n SbVariable,\n SbVariablePersistence,\n} from "@superblocksteam/library";\n\nexport const Page1Scope = createSbScope<{\n OrdersTable: any;\n EditOrderModal: any;\n EditOrderCustomerName: any;\n EditOrderCustomerEmail: any;\n EditOrderAmount: any;\n EditOrderStatus: any;\n EditOrderNotes: any;\n OrdersStateVar: any;\n}>(\n () => ({\n OrdersStateVar: SbVariable({\n defaultValue: [\n {\n id: 1,\n customerName: "John Doe",\n customerEmail: "john@example.com",\n amount: 150.0,\n status: "pending",\n notes: "Rush order",\n createdAt: "2024-01-15T10:30:00Z",\n },\n {\n id: 2,\n customerName: "Jane Smith",\n customerEmail: "jane@example.com",\n amount: 89.99,\n status: "delivered",\n notes: "",\n createdAt: "2024-01-14T14:20:00Z",\n },\n ],\n persistence: SbVariablePersistence.TEMPORARY,\n }),\n }),\n {\n name: "Page1",\n },\n);\n\nexport const Page1 = Page1Scope.entities;\n```\n\n#### Alternative Population Method - Button with State Variable\n\nHere\'s another common pattern where a button populates form fields from a state variable:\n\n```tsx\n// Button that loads selected user data into edit form\n<SbButton\n label="Edit Selected User"\n onClick={SbEventFlow.runJS(() => {\n const selectedUser = SelectedUserStateVar.value;\n\n // Populate form fields from state variable\n EditUserName.text = selectedUser.name;\n EditUserEmail.text = selectedUser.email;\n EditUserRole.metaSelectedOptionValue = selectedUser.role;\n EditUserDepartment.text = selectedUser.department;\n }).controlModal("EditUserModal", "open")}\n/>\n```\n\n### Key Form Patterns\n\n1. **Create Forms**: Start with empty fields, populate from user input\n2. **Edit Forms**: Pre-populate fields with existing data from various sources\n3. **Field Population Methods**:\n - **Table Row Selection**: Use `onRowClick` to set form field values to `{TableName}.selectedRow.{columnName}` (most common)\n - **Button Actions**: Use button clicks to populate from state variables or API responses\n - **API Loading**: Fetch data and populate fields when modal opens\n - **State Variables**: Populate from existing application state\n4. **Form Validation**: Use `required={true}` on form components and validate in submit handlers\n5. **Form Reset**: Always reset form fields when canceling or after successful submission\n6. **Modal Control**: Prefer `SbEventFlow.controlModal()` over directly setting modal open property\n\n### Form Layout Best Practices\n\n- **Container Structure**: Always wrap forms in `SbContainer` with `layout="vertical"`\n- **Consistent Spacing**: Use `spacing={Dim.px(12)}` for form field spacing\n- **Full Width**: Make form fields and containers `width={Dim.fill()}` for proper alignment\n- **Modal Structure**: Use header, content, and footer containers with appropriate spacing\n- **Button Alignment**: Use `horizontalAlign="right"` for the footer containers in modals that contain buttons\n';
55
+ var content7 = '### Form Layouts in Superblocks\n\n**\u{1F6A8} CRITICAL: Remember that sbComputed cannot be used as React children.** When building forms, all dynamic content must be in component properties (like `text={}`, `label={}`) not as children.\n\nWhen creating forms using form field components, follow these rules:\n\n1. Always put form components together inside an `SbContainer` with `layout="vertical"`, `width={Dim.fill()}`, and appropriate `spacing`\n2. Use `spacing={Dim.px(12)}` or similar for consistent form field spacing\n3. Do not change the label position on form components (like `SbInput`). The default is the label is above the input and we want to keep that\n4. Make all form field components and any container parents be `width={Dim.fill()}` so they are all aligned horizontally and easy to use\n\n**Example:**\n\n```jsx\n<SbContainer layout="vertical" width={Dim.fill()} spacing={Dim.px(12)}>\n <SbInput label="First Name" bind={FirstName} width={Dim.fill()} />\n <SbInput label="Last Name" bind={LastName} width={Dim.fill()} />\n <SbInput label="Email" bind={Email} inputType="EMAIL" width={Dim.fill()} />\n</SbContainer>\n```\n\n### Forms inside Modals\n\nIt\'s common to put a form inside a Modal, like for creating or editing an entity. Here are comprehensive examples showing different patterns:\n\n#### Basic Create Form Modal\n\n```tsx\n// Import required components and utilities\nimport {\n SbModal,\n SbContainer,\n SbText,\n SbInput,\n SbDropdown,\n SbButton,\n Dim,\n SbEventFlow,\n} from "@superblocksteam/library";\nimport { Page1 } from "./scope";\n\n// ...\n\nconst {\n NewOrderCustomerName,\n NewOrderCustomerEmail,\n NewOrderAmount,\n NewOrderStatus,\n NewOrderNotes,\n OrdersStateVar,\n CreateOrderModal,\n} = Page1;\n\n<SbModal bind={CreateOrderModal}>\n <SbContainer layout="vertical" width={Dim.fill()} spacing={Dim.px(24)}>\n {/* Modal Header */}\n <SbContainer layout="vertical" spacing={Dim.px(8)}>\n <SbText\n text="Create New Order"\n textStyle={{\n variant: "heading4",\n }}\n />\n <SbText text="Fill out the form below to create a new order" />\n </SbContainer>\n\n {/* Form Content */}\n <SbContainer layout="vertical" width={Dim.fill()} spacing={Dim.px(12)}>\n <SbInput\n bind={NewOrderCustomerName}\n width={Dim.fill()}\n label="Customer Name"\n placeholderText="Enter customer name"\n required={true}\n />\n\n <SbInput\n bind={NewOrderCustomerEmail}\n width={Dim.fill()}\n label="Customer Email"\n inputType="EMAIL"\n placeholderText="Enter customer email"\n required={true}\n />\n\n <SbInput\n bind={NewOrderAmount}\n width={Dim.fill()}\n label="Order Amount"\n placeholderText="Enter order amount"\n inputType="NUMBER"\n required={true}\n />\n\n <SbDropdown\n bind={NewOrderStatus}\n width={Dim.fill()}\n label="Order Status"\n options={[\n {\n label: "Pending",\n value: "pending",\n },\n {\n label: "Processing",\n value: "processing",\n },\n {\n label: "En route",\n value: "en_route",\n },\n {\n label: "Delivered",\n value: "delivered",\n },\n {\n label: "Refunded",\n value: "refunded",\n },\n ]}\n required={true}\n />\n\n <SbInput\n bind={NewOrderNotes}\n width={Dim.fill()}\n label="Order Notes"\n placeholderText="Optional notes about the order"\n multiline={true}\n />\n </SbContainer>\n\n {/* Modal Footer */}\n <SbContainer\n layout="horizontal"\n horizontalAlign="right"\n spacing={Dim.px(12)}\n width={Dim.fill()}\n >\n <SbButton\n label="Cancel"\n variant="secondary"\n onClick={SbEventFlow.runJS(() => {\n // Reset form components\n NewOrderCustomerName.text = "";\n NewOrderCustomerEmail.text = "";\n NewOrderAmount.text = "";\n NewOrderStatus.metaSelectedOptionValue = "";\n NewOrderNotes.text = "";\n })\n // Note how we prefer use controlModal for handling opening/closing\n // the modal rather than setting the modal\'s open property directly\n .controlModal(CreateOrderModal, "close")}\n />\n <SbButton\n label="Create Order"\n variant="primary"\n onClick={SbEventFlow.runJS(() => {\n // Create new order using the form values\n const newOrder = {\n id: `ORD_${Math.floor(Math.random() * 10000)\n .toString()\n .padStart(4, "0")}`,\n customerName: NewOrderCustomerName.value,\n customerEmail: NewOrderCustomerEmail.value,\n amount: NewOrderAmount.value,\n status: NewOrderStatus.selectedOptionValue,\n notes: NewOrderNotes.value,\n createdAt: new Date().toISOString(),\n };\n\n // Add to orders list or call API\n OrdersStateVar.setValue([...OrdersStateVar.value, newOrder]);\n\n // Reset form components\n NewOrderCustomerName.text = "";\n NewOrderCustomerEmail.text = "";\n NewOrderAmount.text = "";\n NewOrderStatus.metaSelectedOptionValue = "";\n NewOrderNotes.text = "";\n })\n // Note how we prefer use controlModal for handling opening/closing\n // the modal rather than setting the modal\'s open property directly\n .controlModal(CreateOrderModal, "close")}\n />\n </SbContainer>\n </SbContainer>\n</SbModal>;\n```\n\n#### Table with Edit Form Modal\n\nThis example shows a more complete pattern where a table displays data and clicking a row opens an edit modal with the form fields pre-populated:\n\n```tsx\n// Import required components and utilities\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbTable,\n SbModal,\n SbContainer,\n SbText,\n SbInput,\n SbDropdown,\n SbButton,\n Dim,\n SbEventFlow,\n sbComputed,\n} from "@superblocksteam/library";\nimport { Page1 } from "./scope";\n\nconst {\n OrdersTable,\n EditOrderModal,\n EditOrderCustomerName,\n EditOrderCustomerEmail,\n EditOrderAmount,\n EditOrderStatus,\n EditOrderNotes,\n OrdersStateVar,\n} = Page1;\n\n// Main page with table\n<SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()} spacing={Dim.px(24)}>\n <SbText\n text="Orders Management"\n textStyle={{ variant: "heading2" }}\n />\n\n <SbTable\n bind={OrdersTable}\n tableData={sbComputed(() => OrdersStateVar.value)}\n onRowClick={SbEventFlow.runJS(() => {\n // Populate form fields with the selected row data\n EditOrderCustomerName.text = OrdersTable.selectedRow.customerName;\n EditOrderCustomerEmail.text = OrdersTable.selectedRow.customerEmail;\n EditOrderAmount.text = OrdersTable.selectedRow.amount;\n EditOrderStatus.metaSelectedOptionValue = OrdersTable.selectedRow.status;\n EditOrderNotes.text = OrdersTable.selectedRow.notes || "";\n })\n // Open the edit modal\n .controlModal(EditOrderModal, "open")}\n width={Dim.fill()}\n height={Dim.fill()}\n />\n </SbColumn>\n </SbSection>\n</SbPage>\n\n// Edit modal with form pre-populated from table row\n<SbModal bind={EditOrderModal}>\n <SbContainer layout="vertical" width={Dim.fill()} spacing={Dim.px(24)}>\n {/* Modal Header */}\n <SbContainer layout="vertical" spacing={Dim.px(8)}>\n <SbText\n text="Edit Order"\n textStyle={{\n variant: "heading4",\n }}\n />\n <SbText text="Update the order details below" />\n </SbContainer>\n\n {/* Form Content - Fields are pre-populated by onRowClick */}\n <SbContainer layout="vertical" width={Dim.fill()} spacing={Dim.px(12)}>\n <SbInput\n bind={EditOrderCustomerName}\n width={Dim.fill()}\n label="Customer Name"\n placeholderText="Enter customer name"\n required={true}\n />\n\n <SbInput\n bind={EditOrderCustomerEmail}\n width={Dim.fill()}\n label="Customer Email"\n inputType="EMAIL"\n placeholderText="Enter customer email"\n required={true}\n />\n\n <SbInput\n bind={EditOrderAmount}\n width={Dim.fill()}\n label="Order Amount"\n placeholderText="Enter order amount"\n inputType="NUMBER"\n required={true}\n />\n\n <SbDropdown\n bind={EditOrderStatus}\n width={Dim.fill()}\n label="Order Status"\n options={[\n {\n label: "Pending",\n value: "pending",\n },\n {\n label: "Processing",\n value: "processing",\n },\n {\n label: "En route",\n value: "en_route",\n },\n {\n label: "Delivered",\n value: "delivered",\n },\n {\n label: "Refunded",\n value: "refunded",\n },\n ]}\n required={true}\n />\n\n <SbInput\n bind={EditOrderNotes}\n width={Dim.fill()}\n label="Order Notes"\n placeholderText="Optional notes about the order"\n multiline={true}\n />\n </SbContainer>\n\n {/* Modal Footer */}\n <SbContainer\n layout="horizontal"\n horizontalAlign="right"\n spacing={Dim.px(12)}\n width={Dim.fill()}\n >\n <SbButton\n label="Cancel"\n variant="secondary"\n onClick={SbEventFlow.controlModal(EditOrderModal, "close")}\n />\n <SbButton\n label="Save Changes"\n variant="primary"\n onClick={SbEventFlow.runJS(() => {\n // Find and update the order in the orders array\n const updatedOrders = OrdersStateVar.value.map(order => {\n if (order.id === OrdersTable.selectedRow.id) {\n return {\n ...order,\n customerName: EditOrderCustomerName.value,\n customerEmail: EditOrderCustomerEmail.value,\n amount: EditOrderAmount.value,\n status: EditOrderStatus.selectedOptionValue,\n notes: EditOrderNotes.value,\n updatedAt: new Date().toISOString(),\n };\n }\n return order;\n });\n\n // Update the orders state\n OrdersStateVar.setValue(updatedOrders);\n })\n .controlModal(EditOrderModal, "close")}\n />\n </SbContainer>\n </SbContainer>\n</SbModal>\n```\n\n**Corresponding scope.ts file for the table + edit modal example:**\n\n```ts\n// pages/Page1/scope.ts\nimport {\n createSbScope,\n SbVariable,\n SbVariablePersistence,\n} from "@superblocksteam/library";\n\nexport const Page1Scope = createSbScope<{\n OrdersTable: any;\n EditOrderModal: any;\n EditOrderCustomerName: any;\n EditOrderCustomerEmail: any;\n EditOrderAmount: any;\n EditOrderStatus: any;\n EditOrderNotes: any;\n OrdersStateVar: any;\n}>(\n () => ({\n OrdersStateVar: SbVariable({\n defaultValue: [\n {\n id: 1,\n customerName: "John Doe",\n customerEmail: "john@example.com",\n amount: 150.0,\n status: "pending",\n notes: "Rush order",\n createdAt: "2024-01-15T10:30:00Z",\n },\n {\n id: 2,\n customerName: "Jane Smith",\n customerEmail: "jane@example.com",\n amount: 89.99,\n status: "delivered",\n notes: "",\n createdAt: "2024-01-14T14:20:00Z",\n },\n ],\n persistence: SbVariablePersistence.TEMPORARY,\n }),\n }),\n {\n name: "Page1",\n },\n);\n\nexport const Page1 = Page1Scope.entities;\n```\n\n#### Alternative Population Method - Button with State Variable\n\nHere\'s another common pattern where a button populates form fields from a state variable:\n\n```tsx\n// Button that loads selected user data into edit form\n<SbButton\n label="Edit Selected User"\n onClick={SbEventFlow.runJS(() => {\n const selectedUser = SelectedUserStateVar.value;\n\n // Populate form fields from state variable\n EditUserName.text = selectedUser.name;\n EditUserEmail.text = selectedUser.email;\n EditUserRole.metaSelectedOptionValue = selectedUser.role;\n EditUserDepartment.text = selectedUser.department;\n }).controlModal(EditUserModal, "open")}\n/>\n```\n\n### Key Form Patterns\n\n1. **Create Forms**: Start with empty fields, populate from user input\n2. **Edit Forms**: Pre-populate fields with existing data from various sources\n3. **Field Population Methods**:\n - **Table Row Selection**: Use `onRowClick` to set form field values to `{TableName}.selectedRow.{columnName}` (most common)\n - **Button Actions**: Use button clicks to populate from state variables or API responses\n - **API Loading**: Fetch data and populate fields when modal opens\n - **State Variables**: Populate from existing application state\n4. **Form Validation**: Use `required={true}` on form components and validate in submit handlers\n5. **Form Reset**: Always reset form fields when canceling or after successful submission\n6. **Modal Control**: Prefer `SbEventFlow.controlModal()` over directly setting modal open property\n\n### Form Layout Best Practices\n\n- **Container Structure**: Always wrap forms in `SbContainer` with `layout="vertical"`\n- **Consistent Spacing**: Use `spacing={Dim.px(12)}` for form field spacing\n- **Full Width**: Make form fields and containers `width={Dim.fill()}` for proper alignment\n- **Modal Structure**: Use header, content, and footer containers with appropriate spacing\n- **Button Alignment**: Use `horizontalAlign="right"` for the footer containers in modals that contain buttons\n';
56
56
 
57
57
  // ../../../vite-plugin-file-sync/dist/ai-service/prompts/generated/subprompts/superblocks-layouts.js
58
58
  init_cjs_shims();
@@ -182,7 +182,7 @@ var content31 = '## Dim\n\nThe `Dim` class is used to define dimensions for size
182
182
 
183
183
  // ../../../vite-plugin-file-sync/dist/ai-service/prompts/generated/library-typedefs/SbEventFlow.js
184
184
  init_cjs_shims();
185
- var content32 = '## SbEventFlow\n\nThe `SbEventFlow` class is used to define responses to events triggered on components (like onClick) in Superblocks. It has a number of methods that can be chained together.\n\n```typescript\nclass SbEventFlow {\n // Run custom JavaScript code\n static runJS(handler: () => void): SbEventFlow;\n runJS(handler: () => void): this;\n\n // Navigation methods\n static navigateTo(props: { url: string; newWindow?: boolean }): SbEventFlow;\n navigateTo(props: { url: string; newWindow?: boolean }): this;\n\n static navigateToApp(appId: string): SbEventFlow;\n navigateToApp(appId: string): this;\n\n static navigateToRoute(route: string): SbEventFlow;\n navigateToRoute(route: string): this;\n\n static setQueryParams(\n params: Record<string, string>,\n keepQueryParams?: boolean,\n ): SbEventFlow;\n setQueryParams(\n params: Record<string, string>,\n keepQueryParams?: boolean,\n ): this;\n\n // Control whether modals are opened or closed\n // modalId should be the name of the string value of the bind property on the modal component\n static controlModal(modalId: string, action: "open" | "close"): SbEventFlow;\n controlModal(modalId: string, action: "open" | "close"): this;\n\n static controlTimer(\n timerId: string,\n action: "start" | "stop" | "toggle",\n ): SbEventFlow;\n controlTimer(timerId: string, action: "start" | "stop" | "toggle"): this;\n\n // API methods\n static runApis(\n apis: SbApi[],\n onSuccess?: SbEventFlow,\n onError?: SbEventFlow,\n ): SbEventFlow;\n runApis(apis: SbApi[], onSuccess?: SbEventFlow, onError?: SbEventFlow): this;\n\n static cancelApis(apiNames: string[], onCancel?: SbEventFlow): SbEventFlow;\n cancelApis(apiNames: string[], onCancel?: SbEventFlow): this;\n\n // Component and state manipulation\n static resetComponent(\n widget: { id: string },\n propertyName: string,\n resetChildren: boolean,\n ): SbEventFlow;\n resetComponent(\n widget: { id: string },\n propertyName: string,\n resetChildren: boolean,\n ): this;\n\n static resetStateVar(stateVar: SbVariable): SbEventFlow;\n resetStateVar(stateVar: SbVariable): this;\n\n static setStateVar(stateVar: SbVariable, value: any): SbEventFlow;\n setStateVar(stateVar: SbVariable, value: any): this;\n\n static setComponentProperty(\n widget: { id: string },\n propertyName: string,\n value: any,\n ): SbEventFlow;\n setComponentProperty(\n widget: { id: string },\n propertyName: string,\n value: any,\n ): this;\n\n // Utility methods\n static showAlert(\n message: string,\n alertType: "info" | "success" | "warning" | "error",\n ): SbEventFlow;\n showAlert(\n message: string,\n alertType: "info" | "success" | "warning" | "error",\n ): this;\n\n static setProfile(\n profileId: string,\n profileAction: "set" | "unset",\n ): SbEventFlow;\n setProfile(profileId: string, profileAction: "set" | "unset"): this;\n\n static triggerEvent(\n eventName: string,\n eventData: Record<string, string>,\n ): SbEventFlow;\n triggerEvent(eventName: string, eventData: Record<string, string>): this;\n}\n```\n';
185
+ var content32 = '## SbEventFlow\n\nThe `SbEventFlow` class is used to define responses to events triggered on components (like onClick) in Superblocks. It has a number of methods that can be chained together.\n\n```typescript\nclass SbEventFlow {\n // Run custom JavaScript code\n static runJS(handler: () => void): SbEventFlow;\n runJS(handler: () => void): this;\n\n // Navigation methods\n static navigateTo(props: { url: string; newWindow?: boolean }): SbEventFlow;\n navigateTo(props: { url: string; newWindow?: boolean }): this;\n\n static navigateToApp(appId: string): SbEventFlow;\n navigateToApp(appId: string): this;\n\n static navigateToRoute(route: string): SbEventFlow;\n navigateToRoute(route: string): this;\n\n static setQueryParams(\n params: Record<string, string>,\n keepQueryParams?: boolean,\n ): SbEventFlow;\n setQueryParams(\n params: Record<string, string>,\n keepQueryParams?: boolean,\n ): this;\n\n // Control whether modals are opened or closed\n // Pass the bound modal component directly rather than its id\n static controlModal(\n modal: WithBindingIdentifier,\n action: "open" | "close",\n ): SbEventFlow;\n controlModal(modal: WithBindingIdentifier, action: "open" | "close"): this;\n\n static controlTimer(\n timerId: string,\n action: "start" | "stop" | "toggle",\n ): SbEventFlow;\n controlTimer(timerId: string, action: "start" | "stop" | "toggle"): this;\n\n // API methods\n static runApis(\n apis: SbApi[],\n onSuccess?: SbEventFlow,\n onError?: SbEventFlow,\n ): SbEventFlow;\n runApis(apis: SbApi[], onSuccess?: SbEventFlow, onError?: SbEventFlow): this;\n\n static cancelApis(apiNames: string[], onCancel?: SbEventFlow): SbEventFlow;\n cancelApis(apiNames: string[], onCancel?: SbEventFlow): this;\n\n // Component and state manipulation\n static resetComponent(\n widget: { id: string },\n propertyName: string,\n resetChildren: boolean,\n ): SbEventFlow;\n resetComponent(\n widget: { id: string },\n propertyName: string,\n resetChildren: boolean,\n ): this;\n\n static resetStateVar(stateVar: SbVariable): SbEventFlow;\n resetStateVar(stateVar: SbVariable): this;\n\n static setStateVar(stateVar: SbVariable, value: any): SbEventFlow;\n setStateVar(stateVar: SbVariable, value: any): this;\n\n static setComponentProperty(\n widget: { id: string },\n propertyName: string,\n value: any,\n ): SbEventFlow;\n setComponentProperty(\n widget: { id: string },\n propertyName: string,\n value: any,\n ): this;\n\n // Utility methods\n static showAlert(\n message: string,\n alertType: "info" | "success" | "warning" | "error",\n ): SbEventFlow;\n showAlert(\n message: string,\n alertType: "info" | "success" | "warning" | "error",\n ): this;\n\n static setProfile(\n profileId: string,\n profileAction: "set" | "unset",\n ): SbEventFlow;\n setProfile(profileId: string, profileAction: "set" | "unset"): this;\n\n static triggerEvent(\n eventName: string,\n eventData: Record<string, string>,\n ): SbEventFlow;\n triggerEvent(eventName: string, eventData: Record<string, string>): this;\n}\n```\n';
186
186
  export {
187
187
  library_components_exports as library_components,
188
188
  library_typedefs_exports as library_typedefs,
package/dist/index.js CHANGED
@@ -393072,7 +393072,7 @@ init_cjs_shims();
393072
393072
  init_cjs_shims();
393073
393073
  var generated = {};
393074
393074
  try {
393075
- generated = await import("./generated-W6HVWB2O.js");
393075
+ generated = await import("./generated-36L7KYTH.js");
393076
393076
  } catch (_error) {
393077
393077
  getLogger().warn("[ai-service] Generated markdown modules not found. Run `pnpm generate:markdown` first.");
393078
393078
  }
@@ -418477,7 +418477,7 @@ var import_util28 = __toESM(require_dist3(), 1);
418477
418477
  // ../sdk/package.json
418478
418478
  var package_default = {
418479
418479
  name: "@superblocksteam/sdk",
418480
- version: "2.0.3-next.217",
418480
+ version: "2.0.3-next.219",
418481
418481
  type: "module",
418482
418482
  description: "Superblocks JS SDK",
418483
418483
  homepage: "https://www.superblocks.com",
@@ -418519,8 +418519,8 @@ var package_default = {
418519
418519
  "@rollup/wasm-node": "^4.35.0",
418520
418520
  "@superblocksteam/bucketeer-sdk": "0.5.0",
418521
418521
  "@superblocksteam/shared": "0.9160.0",
418522
- "@superblocksteam/util": "2.0.3-next.217",
418523
- "@superblocksteam/vite-plugin-file-sync": "2.0.3-next.217",
418522
+ "@superblocksteam/util": "2.0.3-next.219",
418523
+ "@superblocksteam/vite-plugin-file-sync": "2.0.3-next.219",
418524
418524
  "@vitejs/plugin-react": "^4.3.4",
418525
418525
  axios: "^1.4.0",
418526
418526
  chokidar: "^4.0.3",
@@ -426006,7 +426006,7 @@ async function startVite({ app, httpServer: httpServer2, root: root2, mode, port
426006
426006
  };
426007
426007
  const isCustomBuildEnabled2 = await isCustomComponentsEnabled();
426008
426008
  const customFolder = path36.join(root2, "custom");
426009
- const cdnUrl = "https://assets-cdn.superblocks.com/library/2.0.3-next.217";
426009
+ const cdnUrl = "https://assets-cdn.superblocks.com/library/2.0.3-next.219";
426010
426010
  const env3 = loadEnv(mode, root2, "");
426011
426011
  const hmrPort = await getFreePort();
426012
426012
  const hmrOptions = {
@@ -585,5 +585,5 @@
585
585
  "strict": true
586
586
  }
587
587
  },
588
- "version": "2.0.3-next.217"
588
+ "version": "2.0.3-next.219"
589
589
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superblocksteam/cli",
3
- "version": "2.0.3-next.217",
3
+ "version": "2.0.3-next.219",
4
4
  "type": "module",
5
5
  "description": "Official Superblocks CLI",
6
6
  "homepage": "https://www.superblocks.com",
@@ -42,9 +42,9 @@
42
42
  "devDependencies": {
43
43
  "@eslint/js": "^9.16.0",
44
44
  "@oclif/test": "^4.1.11",
45
- "@superblocksteam/sdk": "2.0.3-next.217",
45
+ "@superblocksteam/sdk": "2.0.3-next.219",
46
46
  "@superblocksteam/shared": "0.9160.0",
47
- "@superblocksteam/util": "2.0.3-next.217",
47
+ "@superblocksteam/util": "2.0.3-next.219",
48
48
  "@types/babel__core": "^7.20.0",
49
49
  "@types/chai": "^4",
50
50
  "@types/fs-extra": "^11.0.1",