Skip to content
Merged
2 changes: 1 addition & 1 deletion bestax-mcp/data/catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@
"category": "elements",
"purpose": "The `Notification` component is a Bulma-styled alert/message area for providing feedback, warnings, or information to users.",
"slug": "elements/notification",
"import": "import { Notification } from '@allxsmith/bestax-bulma';",
"import": "import { Notification, NotificationContainer, notification } from '@allxsmith/bestax-bulma';",
"compound": false,
"propCount": 7,
"exampleCount": 7
Expand Down
4 changes: 2 additions & 2 deletions bestax-mcp/data/components/Notification.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@
"code": "<Notification color=\"warning\">\n <Strong>Warning!</Strong> This notification contains{' '}\n <Link href=\"#\">custom content</Link>.\n</Notification>"
}
],
"accessibility": "- **Delete button:** Includes `aria-label=\"Close notification\"` for screen readers.\n- **Keyboard:** The delete button is focusable and can be activated by keyboard.\n- **Content:** Use semantic HTML within the notification for best accessibility.\n\n:::tip\nAlways provide clear, actionable text inside notifications.\n:::",
"accessibility": "- **Delete button:** Includes `aria-label=\"Close notification\"` for screen readers.\n- **Keyboard:** The delete button is focusable and can be activated by keyboard.\n- **Content:** Use semantic HTML within the notification for best accessibility.\n- **Announcements:** A notification shown through `notification` renders with `role=\"alert\"`, announced assertively for `danger` and `warning` and politely otherwise, the way a toast is.\n\n:::tip\nAlways provide clear, actionable text inside notifications.\n:::",
"related": ["Delete", "useBulmaClasses"],
"storybook": "https://bestax.io/storybook/?path=/story/elements-notification--default",
"summary": "The `Notification` component is a Bulma-styled alert/message area for providing feedback, warnings, or information to users.",
"import": "import { Notification } from '@allxsmith/bestax-bulma';",
"import": "import { Notification, NotificationContainer, notification } from '@allxsmith/bestax-bulma';",
"sourceFile": "bulma-ui/src/elements/Notification.tsx",
"rootClass": "notification",
"parts": [
Expand Down
218 changes: 211 additions & 7 deletions bulma-ui/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,216 @@
import * as IndexExports from '../index';

describe('index.ts', () => {
it('exports Button component', () => {
expect(IndexExports.Button).toBeDefined();
});
// The package's public runtime API, in full. `index.ts` re-exports whole
// modules with `export *`, so anything a module exports, even for its own
// tests, ships (#763). Adding or removing a name here is a public-API change:
// make it on purpose, and pick the release type to match. `isBrowser` is
// deprecated and leaves at the next major.
const PUBLIC_EXPORTS = [
'Autocomplete',
'Avatar',
'Avatars',
'Badge',
'Block',
'Box',
'Breadcrumb',
'Button',
'Buttons',
'Card',
'Carousel',
'CarouselItem',
'Cell',
'Checkbox',
'Checkboxes',
'Code',
'Collapse',
'Column',
'Columns',
'ConfigProvider',
'Container',
'Content',
'Control',
'DateInput',
'DateInputBase',
'DateTimeInput',
'DateTimeInputBase',
'Delete',
'Dialog',
'DialogContainer',
'Divider',
'Dropdown',
'DropdownDivider',
'DropdownItem',
'Emphasis',
'Field',
'FieldBody',
'FieldLabel',
'Figure',
'File',
'Footer',
'Grid',
'Hero',
'HeroBody',
'HeroFoot',
'HeroHead',
'Icon',
'IconText',
'Image',
'Input',
'InputBase',
'Level',
'LevelItem',
'LevelLeft',
'LevelRight',
'Link',
'LinkButton',
'ListItem',
'Loading',
'Media',
'MediaContent',
'MediaLeft',
'MediaRight',
'Menu',
'MenuItem',
'MenuLabel',
'MenuList',
'Message',
'Modal',
'Navbar',
'NavbarBrand',
'NavbarBurger',
'NavbarDivider',
'NavbarDropdown',
'NavbarDropdownMenu',
'NavbarEnd',
'NavbarItem',
'NavbarLink',
'NavbarMenu',
'NavbarStart',
'Notification',
'NotificationContainer',
'NumberInput',
'Numberinput',
'OrderedList',
'Pagination',
'PaginationEllipsis',
'PaginationLink',
'PaginationList',
'PaginationNext',
'PaginationPrevious',
'Panel',
'PanelBlock',
'PanelButtonBlock',
'PanelCheckboxBlock',
'PanelHeading',
'PanelIcon',
'PanelInputBlock',
'PanelTabs',
'Paragraph',
'Pre',
'Progress',
'Radio',
'Radios',
'Rate',
'Reveal',
'Section',
'Select',
'SelectBase',
'Sidebar',
'Skeleton',
'Slider',
'Span',
'Step',
'Steps',
'Strong',
'SubTitle',
'Switch',
'Tab',
'TabContentItem',
'TabItem',
'TabList',
'Table',
'Tabs',
'TabsContent',
'Tag',
'TagInput',
'Taginput',
'Tags',
'Tbody',
'Td',
'TextArea',
'TextAreaBase',
'Tfoot',
'Th',
'Thead',
'Theme',
'TimeInput',
'TimeInputBase',
'Title',
'Toast',
'ToastContainer',
'Tooltip',
'Tr',
'UnorderedList',
'checkboxColors',
'checkboxSizes',
'classNames',
'createPrefixedClassNames',
'dialog',
'isBrowser',
'mergeBulmaStyles',
'notification',
'prefixedClassNames',
'radioColors',
'radioSizes',
'switchColors',
'switchSizes',
'toast',
'useBulmaClasses',
'useClassPrefix',
'useColorClasses',
'useColorStyles',
'useConfig',
'useFlexboxClasses',
'useIconLibrary',
'useInsideControl',
'useInsideField',
'useOtherClasses',
'usePrefixedClass',
'usePrefixedClassNames',
'useSpacingClasses',
'useTypographyClasses',
'useVisibilityClasses',
'validAlignContents',
'validAlignItems',
'validAlignSelfs',
'validAlignments',
'validColorShades',
'validColors',
'validCursors',
'validDisplays',
'validFlexDirections',
'validFlexGrowShrink',
'validFlexWraps',
'validFloats',
'validFontFamilies',
'validInteractions',
'validJustifyContents',
'validOverflows',
'validRadii',
'validResponsives',
'validSchemeColors',
'validShadows',
'validSizes',
'validTableColors',
'validTextSizes',
'validTextTransforms',
'validTextWeights',
'validViewports',
'validVisibilities',
];

it('has expected export names', () => {
const exportNames = Object.keys(IndexExports);
expect(exportNames).toContain('Button');
describe('index.ts', () => {
it('exports exactly the public API', () => {
expect(Object.keys(IndexExports).sort()).toEqual(PUBLIC_EXPORTS);
});
});
68 changes: 20 additions & 48 deletions bulma-ui/src/components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,28 +62,6 @@ export interface CardProps
children?: React.ReactNode;
}

/**
* Wrap each footer item in a `.card-footer-item` span.
* @param {CardProps['footer']} footer - Footer content (single node or array).
* @param {string | undefined} classPrefix - Bulma class prefix.
* @returns {React.ReactNode[] | null} Wrapped footer items, or null if no footer.
*/
const renderFooter = (
footer: CardProps['footer'],
classPrefix: string | undefined
) => {
if (!footer) return null;
const items = Array.isArray(footer) ? footer : [footer];
return items.map((item, idx) => (
<span
className={prefixedClassNames(classPrefix, 'card-footer-item')}
key={idx}
>
{item}
</span>
));
};

/**
* Check if children contain any Card compound sub-components.
* @param {React.ReactNode} children - The children to inspect.
Expand Down Expand Up @@ -168,6 +146,9 @@ const CardComponent: React.FC<CardProps> = ({
);
};

// Any falsy footer (including `0`) and an empty array render no footer bar,
// rather than a stray `0` or an empty `.card-footer`.
const hasFooter = Array.isArray(footer) ? footer.length > 0 : Boolean(footer);
return (
<div
className={cardClasses}
Expand Down Expand Up @@ -201,30 +182,24 @@ const CardComponent: React.FC<CardProps> = ({
children !== '' &&
hasCompoundComponents(children) &&
children}
{footer && (
{hasFooter && (
<footer className={prefixedClassNames(classPrefix, 'card-footer')}>
{Array.isArray(footer)
? footer.map((item, idx) => (
<span
className={prefixedClassNames(
classPrefix,
'card-footer-item'
)}
key={idx}
>
{item}
</span>
))
: footer && (
<span
className={prefixedClassNames(
classPrefix,
'card-footer-item'
)}
>
{footer}
</span>
)}
{Array.isArray(footer) ? (
footer.map((item, idx) => (
<span
className={prefixedClassNames(classPrefix, 'card-footer-item')}
key={idx}
>
{item}
</span>
))
) : (
<span
className={prefixedClassNames(classPrefix, 'card-footer-item')}
>
{footer}
</span>
)}
</footer>
)}
</div>
Expand Down Expand Up @@ -652,6 +627,3 @@ export const Card = withSubComponents(
},
'Card'
);

/** Internal test-only exports. Not part of the public API. */
export const __test_exports__ = { renderFooter };
2 changes: 2 additions & 0 deletions bulma-ui/src/components/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {

/**
* Checks if code is running in a browser environment.
* @deprecated Dropdown's internal SSR guard, exported by accident; it will
* be removed in the next major. Check `typeof window !== 'undefined'` instead.
Comment thread
allxsmith marked this conversation as resolved.
Resolved
* @param win - Window object.
* @param doc - Document object.
* @returns {boolean} True if in browser, false otherwise.
Expand Down
Loading
Loading