@lokalise/harmony 1.4.0 → 1.5.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.
Files changed (26) hide show
  1. package/dist/harmony.cjs +1 -1
  2. package/dist/harmony.css +1 -1
  3. package/dist/harmony.mjs +564 -348
  4. package/dist/types/src/components/Sidebar/Sidebar.d.ts +47 -0
  5. package/dist/types/src/components/Sidebar/Sidebar.stories.d.ts +90 -0
  6. package/dist/types/src/components/Sidebar/UpgradeIcon/UpgradeIcon.d.ts +5 -0
  7. package/dist/types/src/components/Sidebar/Widgets/Avatar/Avatar.d.ts +8 -0
  8. package/dist/types/src/components/Sidebar/Widgets/IconLink/IconLink.d.ts +9 -0
  9. package/dist/types/src/components/Sidebar/Widgets/Menu/Menu.d.ts +7 -0
  10. package/dist/types/src/components/Sidebar/Widgets/ProfileMenu/ProfileMenu.d.ts +8 -0
  11. package/dist/types/src/components/Sidebar/Widgets/ProfileMenu/ProfileMenuContent.d.ts +6 -0
  12. package/dist/types/src/components/Sidebar/Widgets/ProfileMenu/ProfileMenuContext.d.ts +3 -0
  13. package/dist/types/src/components/Sidebar/Widgets/ProfileMenu/ProfileMenuProvider.d.ts +7 -0
  14. package/dist/types/src/components/Sidebar/Widgets/ProfileMenu/ProfileSettingsMenuItem/ProfileSettingsMenuItem.d.ts +8 -0
  15. package/dist/types/src/components/Sidebar/Widgets/ProfileMenu/TeamMenuItem/TeamMenuItem.d.ts +8 -0
  16. package/dist/types/src/components/Sidebar/Widgets/ProfileMenu/TeamSwitch/TeamSwitch.d.ts +6 -0
  17. package/dist/types/src/components/Sidebar/Widgets/ProfileMenu/UpgradeMenuItem/UpgradeMenuItem.d.ts +5 -0
  18. package/dist/types/src/components/Sidebar/Widgets/ProfileMenu/types.d.ts +22 -0
  19. package/dist/types/src/components/Sidebar/types.d.ts +14 -0
  20. package/dist/types/src/components/Sidebar/utils/index.d.ts +4 -0
  21. package/dist/types/src/node.d.ts +2 -7
  22. package/dist/types/src/utils/hooks/useEffectOnce.d.ts +5 -0
  23. package/dist/types/src/utils/node.d.ts +6 -0
  24. package/dist/types/src/utils/typeUtils.d.ts +3 -0
  25. package/dist/types/tests/mocks/sidebar/profileMenu.d.ts +2 -0
  26. package/package.json +2 -1
@@ -0,0 +1,47 @@
1
+ import { HTMLProps, PropsWithChildren, ReactNode } from 'react';
2
+ type SidebarProps = HTMLProps<HTMLElement> & {
3
+ children: ReactNode;
4
+ };
5
+ declare const Sidebar: {
6
+ ({ children, ...navProps }: SidebarProps): import("react/jsx-runtime").JSX.Element;
7
+ Top({ children }: PropsWithChildren): import("react/jsx-runtime").JSX.Element;
8
+ Bottom({ children }: PropsWithChildren): import("react/jsx-runtime").JSX.Element;
9
+ Avatar: ({ src, href, ariaLabel, alt }: {
10
+ src: string;
11
+ href?: string;
12
+ ariaLabel?: string;
13
+ alt?: string;
14
+ }) => import("react/jsx-runtime").JSX.Element;
15
+ IconLink: ({ label, to, icon: Icon }: {
16
+ to: string;
17
+ label: string;
18
+ icon: import('react').FC<import('@lokalise/louis').SvgIconProps>;
19
+ }) => import("react/jsx-runtime").JSX.Element;
20
+ Menu: ({ children, icon: Icon }: {
21
+ icon: import('react').FC<import('@lokalise/louis').SvgIconProps>;
22
+ } & {
23
+ children?: ReactNode | undefined;
24
+ }) => import("react/jsx-runtime").JSX.Element;
25
+ ProfileMenu: ({ config, children }: {
26
+ config: import('./Widgets/ProfileMenu/types').SidebarProfileMenuConfig;
27
+ children: import('./Widgets/ProfileMenu/ProfileMenuContent').ProfileMenuContentProps["children"];
28
+ }) => import("react/jsx-runtime").JSX.Element;
29
+ TeamSwitch: ({ onSwitchTeam }: {
30
+ onSwitchTeam: (team: import('./types').SidebarTeam) => void;
31
+ }) => import("react/jsx-runtime").JSX.Element | null;
32
+ TeamMenuItem: ({ team, onClick, hidePlanLabel }: {
33
+ team?: import('./types').SidebarTeam;
34
+ onClick?: (team: import('./types').SidebarTeam) => void;
35
+ hidePlanLabel?: boolean;
36
+ }) => import("react/jsx-runtime").JSX.Element | null;
37
+ UpgradeMenuItem: ({ upgradeOptionHref }: {
38
+ upgradeOptionHref: string;
39
+ }) => import("react/jsx-runtime").JSX.Element | null;
40
+ ProfileSettingsMenuItem: ({ href, onClick, userEmail, hideBottomDivider, }: {
41
+ href: string;
42
+ userEmail: string;
43
+ onClick?: () => void;
44
+ hideBottomDivider?: boolean;
45
+ }) => import("react/jsx-runtime").JSX.Element | null;
46
+ };
47
+ export { Sidebar };
@@ -0,0 +1,90 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { Sidebar } from './Sidebar';
3
+ /**
4
+ * ## Overview
5
+ * Sidebar is a self-contained component using widgets.
6
+ *
7
+ * ## Available Widgets
8
+ *
9
+ * ### `Sidebar.Top`
10
+ * Use to wrap up a top section of the Sidebar
11
+ *
12
+ * ### `Sidebar.Bottom`
13
+ * Use to wrap up a bottom section of the Sidebar
14
+ *
15
+ * ### `Sidebar.Avatar`
16
+ * Display company main avatar / logo in the top section
17
+ * ```
18
+ * src: string;
19
+ * href?: string; ('/')
20
+ * ariaLabel?: string; ('Home')
21
+ * alt?: string; ('Lokalise')
22
+ * ```
23
+ *
24
+ * ### `Sidebar.IconLink`
25
+ * Display link with an icon. Mainly used in the top section
26
+ * ```
27
+ * to: string;
28
+ * label: string;
29
+ * icon: FC<SvgIconProps>
30
+ * ```
31
+ *
32
+ * ### `Sidebar.Menu`
33
+ * Use this widget for simple side menu. Currently utilised for `Help` section
34
+ * ```
35
+ * icon: FC<SvgIconProps>
36
+ * children: ReactNode; (representing menu list)
37
+ * ```
38
+ *
39
+ * ### `Sidebar.ProfileMenu`
40
+ * Contextual component, requires initial configuration
41
+ * ```
42
+ * teams: SidebarTeam[];
43
+ * currentTeamId: number;
44
+ * planId: number;
45
+ * isLimitedView: boolean;
46
+ * isTeamSuspended: boolean;
47
+ * canAccessTeamSettings: boolean;
48
+ * isEndOfTrialActive: boolean;
49
+ * trialDaysLeft: number;
50
+ * isProviderAlpha: boolean;
51
+ * ```
52
+ * and works with internal widgets
53
+ *
54
+ * #### `Sidebar.TeamSwitch`
55
+ * Uses available teams (other than current) and allows user to switch between them
56
+ * ```
57
+ * onSwitchTeam: (team: SidebarTeam) => void;
58
+ * ```
59
+ *
60
+ * #### `Sidebar.TeamMenuItem`
61
+ * Uses context of current team, and depending on ability to switch team or not,
62
+ * it renders as a div or clickable MenuItem. If used with TeamSwitch, it triggers `onSwitchTeams`
63
+ * callback, passing relevant team as an argument
64
+ * ```
65
+ * team?: SidebarTeam; (fallbacks to currentTeam from context if not passed)
66
+ * onClick?: (team: SidebarTeam) => void;
67
+ * hidePlanLabel?: boolean;
68
+ * ```
69
+ *
70
+ * #### `Sidebar.ProfileSettingsMenuItem`
71
+ * Menu item that comes with a small user's email and renders conditionally, only if team
72
+ * is not suspended or is not at the end of a trial
73
+ * ```
74
+ * href: string;
75
+ * userEmail: string;
76
+ * onClick?: () => void; (additional onClick for any tracking events)
77
+ * hideBottomDivider?: boolean;
78
+ * ```
79
+ *
80
+ * #### `Sidebar.UpgradeMenuItem`
81
+ * Menu item conditionally rendering only if `showUpgradeButton` is `true`. It renders correct
82
+ * upgrade note depending on the current team plan and red arrow up to indicate an update option
83
+ * ```
84
+ * upgradeOptionHref: string;
85
+ * ```
86
+ */
87
+ declare const meta: Meta<typeof Sidebar>;
88
+ type Story = StoryObj<typeof Sidebar>;
89
+ export declare const FullSidebar: Story;
90
+ export default meta;
@@ -0,0 +1,5 @@
1
+ type UpgradeIconProps = {
2
+ className?: string;
3
+ };
4
+ export declare const UpgradeIcon: ({ className }: UpgradeIconProps) => import("react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,8 @@
1
+ type AvatarProps = {
2
+ src: string;
3
+ href?: string;
4
+ ariaLabel?: string;
5
+ alt?: string;
6
+ };
7
+ export declare const Avatar: ({ src, href, ariaLabel, alt }: AvatarProps) => import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -0,0 +1,9 @@
1
+ import { SvgIconProps } from '@lokalise/louis';
2
+ import { FC } from 'react';
3
+ type IconLinkProps = {
4
+ to: string;
5
+ label: string;
6
+ icon: FC<SvgIconProps>;
7
+ };
8
+ export declare const IconLink: ({ label, to, icon: Icon }: IconLinkProps) => import("react/jsx-runtime").JSX.Element;
9
+ export {};
@@ -0,0 +1,7 @@
1
+ import { SvgIconProps } from '@lokalise/louis';
2
+ import { FC, PropsWithChildren } from 'react';
3
+ type MenuProps = PropsWithChildren<{
4
+ icon: FC<SvgIconProps>;
5
+ }>;
6
+ export declare const Menu: ({ children, icon: Icon }: MenuProps) => import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,8 @@
1
+ import { ProfileMenuContentProps } from './ProfileMenuContent';
2
+ import { SidebarProfileMenuConfig } from './types';
3
+ type ProfileMenuProps = {
4
+ config: SidebarProfileMenuConfig;
5
+ children: ProfileMenuContentProps['children'];
6
+ };
7
+ export declare const ProfileMenu: ({ config, children }: ProfileMenuProps) => import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -0,0 +1,6 @@
1
+ import { ReactNode } from 'react';
2
+ import { SidebarProfileMenuRenderProps } from './types';
3
+ export type ProfileMenuContentProps = {
4
+ children: (props: SidebarProfileMenuRenderProps) => ReactNode;
5
+ };
6
+ export declare const ProfileMenuContent: ({ children }: ProfileMenuContentProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import { SidebarProfileMenuContextProps } from './types';
2
+ export declare const ProfileMenuContext: import('react').Context<SidebarProfileMenuContextProps>;
3
+ export declare const useProfileMenu: () => SidebarProfileMenuContextProps;
@@ -0,0 +1,7 @@
1
+ import { PropsWithChildren } from 'react';
2
+ import { SidebarProfileMenuConfig } from './types';
3
+ type ProfileMenuProviderProps = PropsWithChildren<{
4
+ config: SidebarProfileMenuConfig;
5
+ }>;
6
+ export declare const ProfileMenuProvider: ({ children, config }: ProfileMenuProviderProps) => import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,8 @@
1
+ type ProfileSettingsMenuItemProps = {
2
+ href: string;
3
+ userEmail: string;
4
+ onClick?: () => void;
5
+ hideBottomDivider?: boolean;
6
+ };
7
+ export declare const ProfileSettingsMenuItem: ({ href, onClick, userEmail, hideBottomDivider, }: ProfileSettingsMenuItemProps) => import("react/jsx-runtime").JSX.Element | null;
8
+ export {};
@@ -0,0 +1,8 @@
1
+ import { SidebarTeam } from '../../../types';
2
+ type TeamMenuItemProps = {
3
+ team?: SidebarTeam;
4
+ onClick?: (team: SidebarTeam) => void;
5
+ hidePlanLabel?: boolean;
6
+ };
7
+ export declare const TeamMenuItem: ({ team, onClick, hidePlanLabel }: TeamMenuItemProps) => import("react/jsx-runtime").JSX.Element | null;
8
+ export {};
@@ -0,0 +1,6 @@
1
+ import { SidebarTeam } from '../../../types';
2
+ type TeamSwitchProps = {
3
+ onSwitchTeam: (team: SidebarTeam) => void;
4
+ };
5
+ export declare const TeamSwitch: ({ onSwitchTeam }: TeamSwitchProps) => import("react/jsx-runtime").JSX.Element | null;
6
+ export {};
@@ -0,0 +1,5 @@
1
+ type UpgradeMenuItemProps = {
2
+ upgradeOptionHref: string;
3
+ };
4
+ export declare const UpgradeMenuItem: ({ upgradeOptionHref }: UpgradeMenuItemProps) => import("react/jsx-runtime").JSX.Element | null;
5
+ export {};
@@ -0,0 +1,22 @@
1
+ import { SidebarTeam } from '../../types';
2
+ export type SidebarProfileMenuConfig = {
3
+ teams: SidebarTeam[];
4
+ currentTeamId: number;
5
+ planId: number;
6
+ isLimitedView: boolean;
7
+ isTeamSuspended: boolean;
8
+ canAccessTeamSettings: boolean;
9
+ isEndOfTrialActive: boolean;
10
+ trialDaysLeft: number;
11
+ isProviderAlpha: boolean;
12
+ };
13
+ export type SidebarProfileMenuContextProps = SidebarProfileMenuConfig & {
14
+ currentTeam?: SidebarTeam;
15
+ otherTeams: SidebarTeam[];
16
+ canChangeBilling: boolean;
17
+ isOnFreeOrTrialPlan: boolean;
18
+ showUpgradeCta: boolean;
19
+ showBillingButton: boolean;
20
+ allowTeamCreation: boolean;
21
+ };
22
+ export type SidebarProfileMenuRenderProps = Pick<SidebarProfileMenuContextProps, 'otherTeams' | 'allowTeamCreation' | 'isLimitedView' | 'canAccessTeamSettings' | 'isEndOfTrialActive' | 'isTeamSuspended' | 'showBillingButton' | 'isProviderAlpha'>;
@@ -0,0 +1,14 @@
1
+ import { TypesFromMap } from '../../utils/node.ts';
2
+ export declare const SidebarTeamRoles: {
3
+ readonly member: "member";
4
+ readonly admin: "admin";
5
+ readonly biller: "biller";
6
+ readonly owner: "owner";
7
+ };
8
+ export type SidebarTeamRole = TypesFromMap<typeof SidebarTeamRoles>;
9
+ export type SidebarTeam = {
10
+ id: number;
11
+ name: string;
12
+ role: SidebarTeamRole;
13
+ logoUrl: string;
14
+ };
@@ -0,0 +1,4 @@
1
+ export declare const splitFileName: (fileName: string) => {
2
+ name: string;
3
+ extension: string;
4
+ };
@@ -2,12 +2,7 @@
2
2
  * COMPONENTS EXPORTS
3
3
  */
4
4
  export { NavigationPanel } from './components/NavigationPanel/NavigationPanel';
5
+ export { Sidebar } from './components/Sidebar/Sidebar';
5
6
  export { Breadcrumbs } from './components/NavigationPanel/components/Breadcrumbs/Breadcrumbs';
6
7
  export { NavigationTabs } from './components/NavigationPanel/components/NavigationTabs/NavigationTabs';
7
- /**
8
- * UTILITIES EXPORTS
9
- */
10
- export { isPaidPlan, isProPlan, isEnterpriseOpenSourcePlan, isEnterprisePlan, isEssentialPlan, isStartPlan, isFreePlan, isTrialPlan, ENTERPRISE_PLAN_IDS, START_PLAN_IDS, ESSENTIAL_PLAN_IDS, PRO_PLAN_IDS, FREE_PLAN_ID, TRIAL_PLAN_ID, ENTERPRISE_OPENSOURCE_PLAN_ID, } from './utils/billing/plan/plan';
11
- export { convertNewLineToBreakTag } from './utils/content/text/text';
12
- export { makeUrlClickable } from './utils/content/url/url';
13
- export { formatDate, formatDateTz } from './utils/i18n/date/date';
8
+ export * from './utils/node';
@@ -0,0 +1,5 @@
1
+ import { EffectCallback } from 'react';
2
+ /**
3
+ * React hook that runs an effect only once.
4
+ */
5
+ export declare const useEffectOnce: (effect: EffectCallback) => void;
@@ -0,0 +1,6 @@
1
+ export { isPaidPlan, isProPlan, isEnterpriseOpenSourcePlan, isEnterprisePlan, isEssentialPlan, isStartPlan, isFreePlan, isTrialPlan, ENTERPRISE_PLAN_IDS, START_PLAN_IDS, ESSENTIAL_PLAN_IDS, PRO_PLAN_IDS, FREE_PLAN_ID, TRIAL_PLAN_ID, ENTERPRISE_OPENSOURCE_PLAN_ID, } from './billing/plan/plan';
2
+ export { convertNewLineToBreakTag } from './content/text/text';
3
+ export { makeUrlClickable } from './content/url/url';
4
+ export { formatDate, formatDateTz } from './i18n/date/date';
5
+ export { useEffectOnce } from './hooks/useEffectOnce';
6
+ export type { TypesFromMap } from './typeUtils';
@@ -0,0 +1,3 @@
1
+ export type TypesFromMap<T extends {
2
+ [key: string]: string | number;
3
+ }> = T[keyof T];
@@ -0,0 +1,2 @@
1
+ import { SidebarTeam } from '../../../src/components/Sidebar/types';
2
+ export declare const createTeam: () => SidebarTeam;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lokalise/harmony",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "author": {
5
5
  "name": "Lokalise",
6
6
  "url": "https://lokalise.com/"
@@ -41,6 +41,7 @@
41
41
  "devDependencies": {
42
42
  "@biomejs/biome": "^1.9.4",
43
43
  "@chromatic-com/storybook": "^3.2.4",
44
+ "@faker-js/faker": "^9.5.0",
44
45
  "@lokalise/biome-config": "^1.6.1",
45
46
  "@semantic-release/changelog": "^6.0.3",
46
47
  "@semantic-release/commit-analyzer": "^13.0.1",