Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/hip-regions-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudoperators/juno-ui-components": patch
---

Improve component descriptions and prop documentation in editor for better developer experience
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,16 @@ const containerStyles = `
`

/**
* Only needed if you want to build your app's scaffold manually. In most cases it is better to use the AppShell component instead.
* Body of the app. Treat this like the body tag of an html page.
* The `AppBody` component serves as the main container for the body of your application.
* It is specifically useful when you require manual setup of the app's layout, providing
* flexibility and control over the structure of the application body. For most cases,
* consider using the `AppShell` component which encompasses more features suitable for
* typical application scaffolding.
*
* @component
* @param {string} [className] Add custom class name to style the component.
* @param {React.ReactNode} [children] The content to be rendered inside the AppBody.
* @returns {React.ReactElement} A JSX element containing the app's body structure.
*/
export const AppBody: React.FC<AppBodyProps> = ({ className = "", children, ...props }) => {
return (
Expand All @@ -24,8 +32,14 @@ export const AppBody: React.FC<AppBodyProps> = ({ className = "", children, ...p
}

export interface AppBodyProps extends React.HTMLAttributes<HTMLDivElement> {
/** Add custom class name */
/**
* Add custom class name to style the component.
* @default ""
*/
className?: string
/** Pass children nodes */

/**
* The content to be rendered inside the AppBody component.
*/
children?: React.ReactNode
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,6 @@ export default meta
type Story = StoryObj<typeof meta>

export const Body: Story = {
parameters: {
docs: {
description: {
story:
"Only needed if you want to build your app's scaffold manually. In most cases it is better to use the AppShell component instead. Body of the app. Treat this like the body tag of an html page.",
},
},
},
parameters: {},
args: {},
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,27 @@ import { PageFooter } from "../PageFooter/index"
import { HeaderContainer } from "../HeaderContainer/index"

/**
* Body of the app. Treat this like the body tag of an html page.
* The `AppShell` component provides the foundational layout structure for the application.
* It acts similarly to an HTML `body` element, organizing pages with headers, footers,
* navigation, and content areas. For simpler manual layout setup, consider using `AppBody`.
*
* @component
* @param {React.ReactNode} [children] The main content to be rendered within the shell.
* @param {string} [className] Add custom class name to style the component.
* @param {boolean} [embedded] Determines if the app should be rendered in embedded mode,
* reducing layout components to core content. Only the content area and children are rendered
* along with a TopNavigation if provided, excluding header, footer, and remaining layout components.
* @default false
* @param {React.ReactNode} [pageHeader] Pass either a `<PageHeader>` component or a string to be used
* as the application name in the standard page header.
* @default `<PageHeader />`
* @param {React.ReactNode} [pageFooter] If specified, a `<PageFooter>` component; otherwise, defaults to `<PageFooter />`.
* @default `<PageFooter />`
* @param {React.ReactNode} [topNavigation] Optional `<TopNavigation>` component. Only rendered if provided.
* @param {React.ReactNode} [sideNavigation] Optional `<SideNavigation>` component. Only rendered if provided.
* @param {boolean} [fullWidthContent] Indicates whether the main content should span the full viewport width.
* Defaults to `false` unless embedded, allowing content to occupy full width.
* @returns {React.ReactElement} A structured shell containing various sections of the app.
*/
export const AppShell: React.FC<AppShellProps> = ({
children,
Expand All @@ -26,9 +46,9 @@ export const AppShell: React.FC<AppShellProps> = ({
topNavigation,
...props
}) => {
// Determine whether to pass set fullWidth to true in embedded mode or not:
// In embedded mode (i.e. embedded == true), fullWidthContent should default to true, unless explicitly passed as false.
// In non-embedded mode, fullWidthContent should default to false, unless explicitly set to true.
// Determine whether to set fullWidth to true in embedded mode or not:
// In embedded mode (i.e., embedded === true), fullWidthContent defaults to true unless explicitly set to false.
// In non-embedded mode, fullWidthContent defaults to false unless explicitly set to true.
const fullWidthOrDefault = embedded ? fullWidthContent !== false : fullWidthContent === true

return (
Expand All @@ -38,7 +58,7 @@ export const AppShell: React.FC<AppShellProps> = ({
{topNavigation && <HeaderContainer fullWidth={fullWidthOrDefault}>{topNavigation}</HeaderContainer>}
<MainContainer>
<MainContainerInner fullWidth={fullWidthOrDefault} className={`${topNavigation ? "jn:mt-[3.875rem]" : ""}`}>
{sideNavigation && sideNavigation}
{sideNavigation}
<ContentContainer>{children}</ContentContainer>
</MainContainerInner>
</MainContainer>
Expand All @@ -65,21 +85,48 @@ export const AppShell: React.FC<AppShellProps> = ({
}

export interface AppShellProps extends React.HTMLAttributes<HTMLElement> {
/** The main content of the app. */
/**
* The main content of the app.
*/
children?: ReactNode
/** Pass either the `<PageHeader>` component or if you don't need to add any content to the page header pass a string to be used as the app name in the standard page header. */

/**
* Add a custom class name to style the component.
* @default ""
*/
className?: string

/**
* Determines if the app should be rendered in embedded mode, reducing layout components to core content.
* @default false
*/
embedded?: boolean

/**
* Pass either a `<PageHeader>` component or a string to be used as the application name in the standard page header.
* @default `<PageHeader />`
*/
pageHeader?: ReactNode
/** Optional. If specified pass a `<PageFooter>` component. If undefined will use default PageFooter */

/**
* An optional `<PageFooter>` component if specified. Uses the default `<PageFooter />` if undefined.
* @default `<PageFooter />`
*/
pageFooter?: ReactNode
/** Optional. If specified expects a `<TopNavigation>` component. If undefined no top navigation is rendered. */

/**
* Optional `<TopNavigation>` component. Only rendered if provided.
*/
topNavigation?: ReactNode
/** Optional. If specified expects a `<SideNavigation>` component. If undefined no side navigation is rendered. */

/**
* Optional `<SideNavigation>` component. Only rendered if provided.
*/
sideNavigation?: ReactNode
/** Optional: Defaults to false. Set embedded to true if app is to be rendered embedded in another app/page.
* In this case only the content area and children are rendered, a TopNavigation if passed, but no header/footer or remaining layout components */
embedded?: boolean
/** Whether the main page / view content can spread over the full available width of the viewport or not. Default is `false` (resulting in a width-constrained, centred content column on very wide screens) UNLESS the AppShell is rendered with embedded as true, then the main content will be full-width by default. In embedded mode, `fullWidthContent` can still be passed as `false` explicitly. */

/**
* Indicates whether the main content should span the full viewport width.
* Defaults to `false` unless embedded, allowing content to occupy full width.
*/
fullWidthContent?: boolean
/** Add a custom class name */
className?: string
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,23 @@ const Wrapper: React.FC<WrapperProps> = ({ children, shadowRoot, shadowRootMode
}

/**
* This provider acts as a wrapper for Juno apps. It renders a StyleProvider and PortalProvider
* The `AppShellProvider` component serves as a wrapper for Juno apps. It integrates both
* `StyleProvider` and `PortalProvider`, offering consistent theming and managing portals across the app.
* This provider can optionally render within a `ShadowRoot` to encapsulate styles independently.
*
* @component
* @param {boolean} [shadowRoot] Determines if the app should be encapsulated within a `ShadowRoot`.
* This is useful for isolating styles and components, especially when embedding the app.
* Defaults to `true`.
* @param {string} [shadowRootMode] Sets the mode of the `ShadowRoot`. Common values are `"open"` or `"closed"`.
* Defaults to `"open"`.
* @param {AppShellStyleWrapper} [stylesWrapper] Specifies where stylesheets are imported.
* Relevant only if `shadowRoot` is `false`. Must be `"inline"` if using a `ShadowRoot`.
* Defaults to `"inline"`.
* @param {string} [theme] Chooses between light or dark theme variants: `"theme-dark"` or `"theme-light"`.
* Uses the globally defined default theme if none specified.
* @param {React.ReactNode} [children] React nodes or a collection of nodes to be rendered within the provider.
* @returns {React.ReactElement} A JSX element wrapping provided children with style and portal management configurations.
*/
export const AppShellProvider: React.FC<AppShellProviderProps> = ({
shadowRoot = true,
Expand All @@ -42,17 +58,37 @@ export const AppShellProvider: React.FC<AppShellProviderProps> = ({
export type AppShellStyleWrapper = "head" | "inline"

interface WrapperProps {
/** React nodes or a collection of React nodes to be rendered as content. */
/**
* React nodes or a collection of React nodes to be rendered as content.
*/
children?: React.ReactNode
/** Whether the app is rendered inside a ShadowRoot. Only choose false if the app is meant to run as a stand-alone application. */

/**
* Determines whether the app is rendered inside a `ShadowRoot`.
* Only set to `false` if the app runs as a standalone application.
* @default true
*/
shadowRoot?: boolean
/** Shadow root mode */

/**
* Specifies the mode of the `ShadowRoot`.
* @default "open"
*/
shadowRootMode?: ShadowRootMode
}

export interface AppShellProviderProps extends WrapperProps {
/** Where app stylesheets are imported. This is only relevant if shadowRoot === false. If you use a ShadowRoot the styles must be inline. */
/**
* Specifies where app stylesheets are imported.
* This is relevant only if `shadowRoot` is `false`. Must be `"inline"` if using a `ShadowRoot`.
* @default "inline"
*/
stylesWrapper?: AppShellStyleWrapper
/** theme: theme-dark or theme-light */

/**
* Determines the theme of the application, choosing between `"theme-dark"` or `"theme-light"`.
* Defaults to the global default theme name.
* @default DEFAULT_THEME_NAME
*/
theme?: "theme-dark" | "theme-light"
}
35 changes: 22 additions & 13 deletions packages/ui-components/src/components/Badge/Badge.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,32 +31,33 @@ export type BadgeVariantType = "default" | "info" | "success" | "warning" | "dan

export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
/**
* Specify an optional semantic variant that determines the appearance of a badge.
* Specify a semantic variant that determines the appearance of the badge.
* @default "default"
*/
variant?: BadgeVariantType

/**
* Optional.
* If true, an icon corresponding to the variant will be displayed.
* If a string is provided and it's a valid icon name, that icon will be displayed.
* Determines whether to display an icon. If set to `true`, an icon related
* to the variant will be used. If a valid string representing a known icon
* is provided, that icon will be displayed.
* @default false
*/
icon?: boolean | KnownIcons

/**
* Pass an optional string of text to be rendered as content.
* Alternatively, content can be passed as children (see below).
* If children are provided, they will take precedence.
* The optional text content of the badge. If children are provided, they take precedence.
*/
text?: string

/**
* Pass an optional CSS class to apply to the message.
* Additional CSS class to apply to the badge.
* @default ""
*/
className?: string

/**
* Pass optional React nodes or a collection of React nodes to be rendered as content.
* Takes precedence over the text property.
* React nodes or a collection of React nodes to be rendered as content, taking
* precedence over the `text` property.
*/
children?: React.ReactNode
}
Expand All @@ -83,9 +84,17 @@ const isValidIcon = (icon: string): icon is KnownIcons => {
}

/**
* A Badge is used to visually represent properties or states of an entity.
* It supports multiple semantic versions, each with distinct styling.
* Optionally, an icon can be included to further emphasize the meaning.
* The `Badge` component visually represents properties or states of an entity.
* It supports multiple semantic variants, each with distinct styling. An optional
* icon can be included to further emphasize meaning.
*
* @component
* @param {BadgeVariantType} [variant="default"] A semantic variant for the badge style.
* @param {boolean | KnownIcons} [icon=false] When true, displays an icon related to the variant. Accepts a valid icon string.
* @param {string} [text] String content to display within the badge. Children take precedence.
* @param {string} [className] Additional class names for styling the badge.
* @param {React.ReactNode} [children] Nodes to render inside the badge, taking precedence over `text`.
* @returns {React.ReactElement} A styled badge element indicating a property or state.
*/
export const Badge: React.FC<BadgeProps> = ({
variant = "default",
Expand Down
24 changes: 18 additions & 6 deletions packages/ui-components/src/components/Box/Box.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,35 @@ const boxPadding = `

export interface BoxProps extends React.HTMLAttributes<HTMLDivElement> {
/**
* Child elements to be rendered inside the Box.
* The child elements to be rendered inside the Box.
*/
children?: React.ReactNode

/**
* If true, padding is removed.
* Determines whether the Box should render without padding.
* When true, padding is removed.
* @default false
*/
unpad?: boolean

/**
* Additional CSS styles to apply to the Box.
* Additional CSS classes to apply to the Box component.
* @default ""
*/
className?: string
}

/**
* A generic Box component with optional padding and a light border.
* Ideal for annotations, additional explanations, and remarks where a Message or InfoBox would be too visually emphasized.
* Typically used for small text but can contain any child elements, as required.
* The `Box` component is a versatile container with optional padding and a subtle border.
* It is perfect for annotations, supplementary explanations, and remarks where more visually
* pronounced components like a MessageBox or InfoBox would be excessive.
* This component typically displays small text but can contain any child elements as required.
*
* @component
* @param {React.ReactNode} [children] Content to be rendered within the Box.
* @param {boolean} [unpad=false] If true, padding is removed from the Box.
* @param {string} [className=""] Custom class names for additional styling of the Box.
* @returns {React.ReactElement} A flexible Box component with optional padding.
*/
export const Box: React.FC<BoxProps> = ({ children, unpad = false, className = "", ...props }) => {
const combinedClassName = `juno-box ${boxStyles} ${!unpad ? boxPadding : ""} ${className}`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,29 @@ import { BreadcrumbItem, BreadcrumbItemProps } from "../BreadcrumbItem/Breadcrum

export interface BreadcrumbProps extends React.HTMLAttributes<HTMLElement> {
/**
* Additional CSS styles to apply to the breadcrumb for custom styling.
* Additional CSS classes for styling the breadcrumb component.
* @default ""
*/
className?: string

/**
* Optional React nodes or a collection of React nodes to be rendered as custom content.
* The BreadcrumbItem component is typically used.
* The `BreadcrumbItem` component is typically used.
*/
children?: React.ReactNode
}

/**
* Breadcrumb is a component that structures navigational links in a breadcrumb trail.
* The `Breadcrumb` component structures navigational links in a breadcrumb trail, providing a way to display
* hierarchical navigation paths. It efficiently manages:
* - Wrapping `BreadcrumbItem` or other custom components to form breadcrumb navigation.
* - Automatic insertion of separator icons between items, enhancing visibility.
* - Filtering out invalid React elements to prevent rendering errors.
*
* This component:
* - Wraps around BreadcrumbItem or other custom components to create breadcrumb navigation.
* - Automatically inserts separator icons between items.
* - Filters out invalid React elements to prevent rendering errors.
* @component
* @param {string} [className=""] Additional CSS classes for custom styling of the breadcrumb.
* @param {React.ReactNode} [children] React nodes or elements that compose the breadcrumb trail. `BreadcrumbItem` is recommended.
* @returns {React.ReactElement} A structured breadcrumb navigation component with separators.
*/
export const Breadcrumb: React.FC<BreadcrumbProps> = ({ children, className = "", ...props }) => {
const childrenArray = Children.toArray(children).filter(React.isValidElement) // Filter out invalid elements
Expand Down
Loading
Loading