@hyphen/hyphen-components 6.1.1 → 6.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.
@@ -1,5 +1,5 @@
1
1
  import { BorderRadiusSize, Breakpoint, BreakpointSizeWithBase } from '../types';
2
- export declare const ICON_NAMES: ("add" | "alarm-disable" | "alarm" | "analytics" | "app-window" | "arrow-down" | "arrow-left" | "arrow-right" | "arrow-up" | "arrows-maximize" | "at" | "ban" | "block" | "blocks" | "book-open" | "c-add" | "c-check" | "c-delete" | "c-in-progress" | "c-info" | "c-question" | "c-remove" | "c-user" | "c-warning" | "calendar-create" | "calendar" | "camera" | "caret-down" | "caret-left" | "caret-right" | "caret-sm-down" | "caret-sm-left" | "caret-sm-right" | "caret-sm-up" | "caret-up-down" | "caret-up" | "chart-bar" | "chart-line" | "chat" | "check" | "checkbox-btn-checked" | "checkbox-btn-indeterminate" | "checkbox-btn" | "circle-filled" | "circle" | "clipboard" | "cloud" | "code" | "command-line" | "computer" | "contact" | "copy-document" | "dashboard" | "database" | "dock-left" | "document" | "dots" | "download" | "electricity-bolt" | "exclamation-mark" | "eye-slash" | "eye" | "filter" | "flag" | "folder" | "gear" | "grab" | "hash-mark" | "heart-o" | "heart" | "home" | "info" | "integrations" | "key" | "launch-app" | "lightbulb" | "link" | "list" | "lock" | "logo-deploy" | "logo-env" | "logo-link" | "logo-netinfo" | "logo-toggle" | "logout" | "mail" | "memory" | "menu" | "minus" | "moon" | "paperclip" | "path-intersect" | "pause" | "pc" | "pencil" | "phone" | "photo" | "play" | "qr-code" | "radio-btn-checked" | "radio-btn-unchecked" | "refresh" | "remove" | "rewind" | "search" | "send" | "settings" | "skip" | "ssd" | "stack" | "star-o" | "star" | "stopwatch" | "subtract" | "sun" | "t-warning" | "tag" | "terminal" | "time-alarm" | "time-clock" | "trash" | "unlocked" | "upload" | "user-create" | "user" | "users" | "wifi-off" | "wifi" | "zoom-in" | "zoom-out")[];
2
+ export declare const ICON_NAMES: ("add" | "alarm-disable" | "alarm" | "analytics" | "app-window" | "arrow-down" | "arrow-left" | "arrow-right" | "arrow-up" | "arrows-maximize" | "at" | "ban" | "block" | "blocks" | "book-open" | "c-add" | "c-check" | "c-delete" | "c-in-progress" | "c-info" | "c-question" | "c-remove" | "c-user" | "c-warning" | "calendar-create" | "calendar" | "camera" | "caret-down" | "caret-left" | "caret-right" | "caret-sm-down" | "caret-sm-left" | "caret-sm-right" | "caret-sm-up" | "caret-up-down" | "caret-up" | "chart-bar" | "chart-line" | "chat" | "check" | "checkbox-btn-checked" | "checkbox-btn-indeterminate" | "checkbox-btn" | "circle-filled" | "circle" | "clipboard" | "cloud" | "code" | "command-line" | "computer" | "contact" | "copy-document" | "cpu" | "dashboard" | "database" | "dock-left" | "document" | "dots" | "download" | "electricity-bolt" | "exclamation-mark" | "eye-slash" | "eye" | "filter" | "flag" | "folder" | "gear" | "grab" | "hash-mark" | "heart-o" | "heart" | "home" | "info" | "integrations" | "key" | "launch-app" | "lightbulb" | "link" | "list" | "lock" | "logo-deploy" | "logo-env" | "logo-github" | "logo-link" | "logo-netinfo" | "logo-toggle" | "logout" | "mail" | "memory" | "menu" | "microphone" | "minus" | "moon" | "paperclip" | "path-intersect" | "pause" | "pc" | "pencil" | "phone" | "photo" | "play" | "qr-code" | "radio-btn-checked" | "radio-btn-unchecked" | "refresh" | "remove" | "rewind" | "search" | "send" | "settings" | "skip" | "ssd" | "stack" | "star-o" | "star" | "stopwatch" | "subtract" | "sun" | "t-warning" | "tag" | "terminal" | "time-alarm" | "time-clock" | "trash" | "unlocked" | "upload" | "user-create" | "user" | "users" | "wifi-off" | "wifi" | "zoom-in" | "zoom-out")[];
3
3
  export declare const BORDER_RADIUS_OPTIONS: BorderRadiusSize[];
4
4
  export declare const BORDER_SIZE_OPTIONS: ("0" | "sm" | "md" | "lg")[];
5
5
  export declare const BREAKPOINT_OPTIONS: BreakpointSizeWithBase[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyphen/hyphen-components",
3
- "version": "6.1.1",
3
+ "version": "6.2.0",
4
4
  "license": "MIT",
5
5
  "author": {
6
6
  "name": "@hyphen"
@@ -62,7 +62,7 @@
62
62
  ],
63
63
  "dependencies": {
64
64
  "@emotion/react": "^11.14.0",
65
- "@hyphen/hyphen-design-tokens": "^5.1.0",
65
+ "@hyphen/hyphen-design-tokens": "^5.2.0",
66
66
  "@radix-ui/react-aspect-ratio": "^1.1.7",
67
67
  "@radix-ui/react-collapsible": "^1.1.12",
68
68
  "@radix-ui/react-dropdown-menu": "^2.1.16",
@@ -0,0 +1,18 @@
1
+ import { render } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { AspectRatio } from './AspectRatio';
4
+
5
+ describe('AspectRatio', () => {
6
+ test('renders children within the aspect ratio box', () => {
7
+ const { container } = render(
8
+ <AspectRatio ratio={16 / 9}>
9
+ <div data-testid="child" />
10
+ </AspectRatio>
11
+ );
12
+
13
+ const wrapper = container.firstChild as HTMLElement;
14
+ expect(wrapper).toBeInTheDocument();
15
+ expect(wrapper.querySelector('[data-testid="child"]')).toBeInTheDocument();
16
+ expect(wrapper.style.position).toBe('relative');
17
+ });
18
+ });
@@ -0,0 +1,22 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import {
4
+ Collapsible,
5
+ CollapsibleTrigger,
6
+ CollapsibleContent,
7
+ } from './Collapsible';
8
+
9
+ describe('Collapsible', () => {
10
+ test('toggles content visibility when trigger is clicked', async () => {
11
+ render(
12
+ <Collapsible>
13
+ <CollapsibleTrigger>Toggle</CollapsibleTrigger>
14
+ <CollapsibleContent>Hidden content</CollapsibleContent>
15
+ </Collapsible>
16
+ );
17
+
18
+ expect(screen.queryByText('Hidden content')).not.toBeInTheDocument();
19
+ fireEvent.click(screen.getByText('Toggle'));
20
+ expect(await screen.findByText('Hidden content')).toBeInTheDocument();
21
+ });
22
+ });
@@ -0,0 +1,23 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import {
4
+ DropdownMenu,
5
+ DropdownMenuTrigger,
6
+ DropdownMenuContent,
7
+ DropdownMenuItem,
8
+ } from './DropdownMenu';
9
+
10
+ describe('DropdownMenu', () => {
11
+ test('renders item when menu is open', () => {
12
+ render(
13
+ <DropdownMenu open>
14
+ <DropdownMenuTrigger>Open</DropdownMenuTrigger>
15
+ <DropdownMenuContent>
16
+ <DropdownMenuItem>Item</DropdownMenuItem>
17
+ </DropdownMenuContent>
18
+ </DropdownMenu>
19
+ );
20
+
21
+ expect(screen.getByText('Item')).toBeInTheDocument();
22
+ });
23
+ });
@@ -0,0 +1,26 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { FormControl } from './FormControl';
4
+
5
+ describe('FormControl', () => {
6
+ test('renders label and error message', () => {
7
+ render(
8
+ <FormControl id="input" label="Label" error="Error">
9
+ <input id="input" />
10
+ </FormControl>
11
+ );
12
+
13
+ expect(screen.getByText('Label')).toBeInTheDocument();
14
+ expect(screen.getByText('Error')).toBeInTheDocument();
15
+ });
16
+
17
+ test('hides label when hideLabel is true', () => {
18
+ render(
19
+ <FormControl id="input" label="Label" hideLabel>
20
+ <input id="input" />
21
+ </FormControl>
22
+ );
23
+
24
+ expect(screen.queryByText('Label')).not.toBeInTheDocument();
25
+ });
26
+ });
@@ -0,0 +1,12 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { HelpText } from './HelpText';
4
+
5
+ describe('HelpText', () => {
6
+ test('renders children with correct class', () => {
7
+ render(<HelpText>Helpful</HelpText>);
8
+ const text = screen.getByText('Helpful');
9
+ expect(text).toBeInTheDocument();
10
+ expect(text).toHaveClass('help-text');
11
+ });
12
+ });
@@ -0,0 +1,18 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { InputValidationMessage } from './InputValidationMessage';
4
+
5
+ describe('InputValidationMessage', () => {
6
+ test('renders message with default size', () => {
7
+ render(<InputValidationMessage>Oops</InputValidationMessage>);
8
+ const msg = screen.getByText('Oops');
9
+ expect(msg).toBeInTheDocument();
10
+ expect(msg).toHaveClass('font-size-sm');
11
+ });
12
+
13
+ test('supports different sizes', () => {
14
+ render(<InputValidationMessage size="md">Big</InputValidationMessage>);
15
+ const msg = screen.getByText('Big');
16
+ expect(msg).toHaveClass('font-size-md');
17
+ });
18
+ });
@@ -0,0 +1,26 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { Sidebar, SidebarProvider, SidebarTrigger } from './Sidebar';
4
+
5
+ jest.mock('../../hooks/useIsMobile/useIsMobile', () => ({
6
+ useIsMobile: () => false,
7
+ }));
8
+
9
+ describe('Sidebar', () => {
10
+ test('toggles open state with trigger', () => {
11
+ render(
12
+ <SidebarProvider>
13
+ <Sidebar data-testid="sidebar">
14
+ <div>Content</div>
15
+ </Sidebar>
16
+ <SidebarTrigger />
17
+ </SidebarProvider>
18
+ );
19
+
20
+ const sidebar = document.querySelector('[data-state]') as HTMLElement;
21
+ expect(sidebar).toHaveAttribute('data-state', 'expanded');
22
+
23
+ fireEvent.click(screen.getByLabelText('toggle sidebar'));
24
+ expect(sidebar).toHaveAttribute('data-state', 'collapsed');
25
+ });
26
+ });
@@ -99,7 +99,7 @@ const SidebarProvider = forwardRef<
99
99
  localStorage.setItem(storageKey, `${newOpenState}`);
100
100
  }
101
101
  },
102
- [setOpenProp, open]
102
+ [setOpenProp, open, storageKey]
103
103
  );
104
104
 
105
105
  // Toggle sidebar based on screen type
@@ -0,0 +1,49 @@
1
+ import { render } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { ThemeProvider, ThemeProviderContext } from './ThemeProvider';
4
+
5
+ beforeAll(() => {
6
+ Object.defineProperty(window, 'matchMedia', {
7
+ writable: true,
8
+ value: jest.fn().mockImplementation(() => ({
9
+ matches: false,
10
+ media: '',
11
+ onchange: null,
12
+ addListener: jest.fn(),
13
+ removeListener: jest.fn(),
14
+ addEventListener: jest.fn(),
15
+ removeEventListener: jest.fn(),
16
+ dispatchEvent: jest.fn(),
17
+ })),
18
+ });
19
+ });
20
+
21
+ describe('ThemeProvider', () => {
22
+ test('applies default theme to document element', () => {
23
+ render(
24
+ <ThemeProvider defaultTheme="light">
25
+ <div />
26
+ </ThemeProvider>
27
+ );
28
+ expect(document.documentElement.classList.contains('light')).toBe(true);
29
+ });
30
+
31
+ test('setTheme updates class and localStorage', () => {
32
+ const Consumer = () => {
33
+ const { setTheme } = React.useContext(ThemeProviderContext);
34
+ React.useEffect(() => {
35
+ setTheme('dark');
36
+ }, [setTheme]);
37
+ return null;
38
+ };
39
+
40
+ render(
41
+ <ThemeProvider defaultTheme="light">
42
+ <Consumer />
43
+ </ThemeProvider>
44
+ );
45
+
46
+ expect(document.documentElement.classList.contains('dark')).toBe(true);
47
+ expect(localStorage.getItem('hyphen-ui-theme')).toBe('dark');
48
+ });
49
+ });
@@ -0,0 +1,13 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { Toggle } from './Toggle';
4
+
5
+ describe('Toggle', () => {
6
+ test('changes state when clicked', () => {
7
+ render(<Toggle>Bold</Toggle>);
8
+ const button = screen.getByRole('button');
9
+ expect(button).toHaveAttribute('data-state', 'off');
10
+ fireEvent.click(button);
11
+ expect(button).toHaveAttribute('data-state', 'on');
12
+ });
13
+ });
@@ -0,0 +1,19 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { ToggleGroup, ToggleGroupItem } from './ToggleGroup';
4
+
5
+ describe('ToggleGroup', () => {
6
+ test('handles selection and displays error message', () => {
7
+ render(
8
+ <ToggleGroup type="single" variant="outline" error="Error">
9
+ <ToggleGroupItem value="a">A</ToggleGroupItem>
10
+ </ToggleGroup>
11
+ );
12
+
13
+ const item = screen.getByText('A');
14
+ expect(item).toHaveClass('outline');
15
+ fireEvent.click(item);
16
+ expect(item).toHaveAttribute('data-state', 'on');
17
+ expect(screen.getByText('Error')).toBeInTheDocument();
18
+ });
19
+ });
@@ -0,0 +1,24 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import {
4
+ Tooltip,
5
+ TooltipTrigger,
6
+ TooltipContent,
7
+ TooltipProvider,
8
+ } from './Tooltip';
9
+
10
+ describe('Tooltip', () => {
11
+ test('renders content when open', () => {
12
+ render(
13
+ <TooltipProvider>
14
+ <Tooltip open>
15
+ <TooltipTrigger>Hover me</TooltipTrigger>
16
+ <TooltipContent>Tip content</TooltipContent>
17
+ </Tooltip>
18
+ </TooltipProvider>
19
+ );
20
+
21
+ const contents = screen.getAllByText('Tip content');
22
+ expect(contents.length).toBeGreaterThan(0);
23
+ });
24
+ });