@luscii-healthtech/web-ui 20.7.0 → 20.8.1

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.
@@ -2,5 +2,16 @@ import React from "react";
2
2
  type DividerProps = React.ComponentPropsWithoutRef<"div"> & {
3
3
  dark?: boolean;
4
4
  };
5
- export declare const Divider: React.FC<DividerProps>;
5
+ type HrProps = React.ComponentPropsWithoutRef<"hr"> & {
6
+ /**
7
+ * Request the v2 version of the divider, which has the following benefits:
8
+ * - Uses an `<hr>` tag instead of a `<div>`.
9
+ * - Uses the border color from the design system, and doesn't have a prop
10
+ * to change it.
11
+ * - Doesn't contain any logic about when it should be hidden.
12
+ */
13
+ version: "v2";
14
+ };
15
+ type Props = DividerProps | HrProps;
16
+ export declare const Divider: React.FC<Props>;
6
17
  export {};
@@ -5,6 +5,10 @@ import type { StepsProps } from "../Steps/Steps";
5
5
  type CRUDPageButtonProps = Pick<BaseButtonProps, "onClick" | "text" | "isDisabled">;
6
6
  type CRUDPageTitle = {
7
7
  text: string;
8
+ /**
9
+ * @deprecated
10
+ * We don't want to show icons in the page title anymore.
11
+ */
8
12
  icon?: string;
9
13
  };
10
14
  type CRUDPageHeader = Omit<PageHeaderProps, "navigation" | "isPolling" | "accessories">;
@@ -15,11 +15,15 @@ type WithPageHeaderBanner = {
15
15
  };
16
16
  };
17
17
  export type PageHeaderProps = {
18
+ /**
19
+ * These are props passed to the `Tabbar` component. The name
20
+ * `navigation` does not convey this well.
21
+ */
18
22
  navigation?: Omit<TabbarProps, "withoutPadding">;
19
23
  breadcrumbs?: BreadcrumbProps["crumbs"];
20
24
  truncateBreadcrumbsAfter?: number;
21
25
  dataTestId?: string;
22
- title: string;
26
+ title: string | React.ReactNode;
23
27
  isPolling?: boolean;
24
28
  className?: string;
25
29
  contained?: boolean;
@@ -9,10 +9,13 @@ export interface TabbarProps<T extends object = Record<string, unknown>> {
9
9
  }) => void;
10
10
  className?: string;
11
11
  /**
12
+ * @deprecated
13
+ * If this component needs padding, it should be added from the code consuming this component.
14
+ *
12
15
  * If this component is being used on a container that will handle spacing, this option disables the padding, allowing the container to take over spacing.
13
16
  */
14
17
  withoutPadding?: boolean;
15
18
  }
16
19
  export { TabItemDetails };
17
- export declare const Tabbar: <T extends object = Record<string, unknown>>({ tabs, selectedIndex, onSelect, className, withoutPadding, }: TabbarProps<T>) => JSX.Element;
20
+ export declare const Tabbar: <T extends object = Record<string, unknown>>({ tabs, selectedIndex, onSelect, className, }: TabbarProps<T>) => JSX.Element;
18
21
  export default Tabbar;
@@ -0,0 +1,6 @@
1
+ import React from "react";
2
+ type Props = React.ComponentPropsWithoutRef<"h1"> & {
3
+ as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
4
+ };
5
+ export declare const PageTitle: React.FC<Props>;
6
+ export {};
@@ -3877,7 +3877,7 @@ const NavLayout = (props) => {
3877
3877
  ]) },
3878
3878
  pageHeader && React__namespace.default.createElement("div", { "data-test-id": "nav-layout-page-header" }, pageHeader),
3879
3879
  React__namespace.default.createElement("div", { "data-test-id": "page-body", className: classNames__default.default({
3880
- "ui-px-4": !!pageHeader,
3880
+ "ui-px-xl": !!pageHeader,
3881
3881
  "ui-h-full": inViewer
3882
3882
  // this allows extra spacing in the small viewport of hix specially when dealing with dropdowns
3883
3883
  }) }, children)
@@ -3886,6 +3886,9 @@ const NavLayout = (props) => {
3886
3886
  };
3887
3887
 
3888
3888
  const Divider = (props) => {
3889
+ if ("version" in props) {
3890
+ return React__namespace.default.createElement(HrDivider, Object.assign({}, props));
3891
+ }
3889
3892
  const { className, dark } = props, rest = __rest(props, ["className", "dark"]);
3890
3893
  const darkTheme = Boolean(dark);
3891
3894
  return React__namespace.default.createElement("div", Object.assign({ className: classNames__default.default("ui-border-color ui-block ui-w-full ui-border-b ui-border-solid last:ui-border-b-0", className, {
@@ -3893,6 +3896,10 @@ const Divider = (props) => {
3893
3896
  "ui-border-slate-600": darkTheme
3894
3897
  }) }, rest));
3895
3898
  };
3899
+ function HrDivider(props) {
3900
+ const { className } = props;
3901
+ return React__namespace.default.createElement("hr", { className: classNames__default.default("ui-border-color-border", className) });
3902
+ }
3896
3903
 
3897
3904
  const NavMenuFooter = ({ text, subtext, visible = true }) => {
3898
3905
  if (!visible) {
@@ -4193,22 +4200,21 @@ const Breadcrumbs = ({ crumbs, truncateAfter = Infinity }) => {
4193
4200
  };
4194
4201
 
4195
4202
  const TabbarItem = ({ title, index, isSelected, onSelect, className, badgeCount = 0, isLoading = false, dataTestId = "" }) => {
4196
- const handleTabClick = () => onSelect && onSelect(index);
4197
- const itemClassName = classNames__default.default("ui-flex first:ui-ml-0 ui-ml-2 ui-flex-row ui-cursor-pointer ui-py-2 ui-px-3 ui-rounded-lg focus:ui-outline-primary ui-transition ui-ease-in ui-duration-150", className, {
4198
- "ui-bg-slate-100 ui-text-slate-800 hover:ui-text-slate-800 focus:ui-text-slate-800": isSelected,
4199
- "ui-bg-slate-50 ui-text-slate-500 hover:ui-bg-slate-100 hover:ui-text-slate-500 focus:ui-text-slate-500 ui-opacity-75": !isSelected
4203
+ const handleTabClick = () => onSelect === null || onSelect === void 0 ? void 0 : onSelect(index);
4204
+ const itemClassName = classNames__default.default("ui-flex ui-items-center ui-py-m", "ui-border-b-2 hover:ui-text-primary", "ui-transition ui-ease-in ui-duration-150", className, {
4205
+ "ui-border-b-transparent ui-text-on-surface": !isSelected,
4206
+ "ui-border-b-primary ui-text-primary": isSelected
4200
4207
  });
4201
4208
  return React__namespace.default.createElement(
4202
- "div",
4209
+ "button",
4203
4210
  { className: itemClassName, onClick: handleTabClick, "data-test-id": dataTestId },
4204
- typeof title === "string" && React__namespace.default.createElement(Text, { text: title, type: isSelected ? "strong" : "base", inline: true, className: "ui-leading-inherit" }),
4205
- typeof title !== "string" && title,
4211
+ typeof title === "string" ? React__namespace.default.createElement(Text, { variant: "strong", color: "current", inline: true, className: "ui-leading-inherit" }, title) : title,
4206
4212
  badgeCount > 0 && React__namespace.default.createElement(Badge, { className: "ui-ml-1", badgeCount }),
4207
4213
  isLoading && React__namespace.default.createElement(LoadingIndicator, { asSpinner: true, spinnerColor: "gray", className: "ui-w-6" })
4208
4214
  );
4209
4215
  };
4210
4216
 
4211
- const Tabbar = ({ tabs = [], selectedIndex, onSelect, className = "", withoutPadding = false }) => {
4217
+ const Tabbar = ({ tabs = [], selectedIndex, onSelect, className }) => {
4212
4218
  const [innerSelectedIndex, setInnerSelectedIndex] = React.useState(selectedIndex);
4213
4219
  React.useEffect(() => {
4214
4220
  setInnerSelectedIndex(selectedIndex);
@@ -4217,51 +4223,79 @@ const Tabbar = ({ tabs = [], selectedIndex, onSelect, className = "", withoutPad
4217
4223
  setInnerSelectedIndex(index);
4218
4224
  onSelect === null || onSelect === void 0 ? void 0 : onSelect({ index, selectedTab: tabs[index] });
4219
4225
  };
4220
- return React__namespace.default.createElement("div", { className: classNames__default.default(`ui-flex ui-w-full ui-flex-row ui-rounded-xl ui-bg-white ${className}`, {
4221
- "ui-p-2": !withoutPadding
4222
- }) }, tabs === null || tabs === void 0 ? void 0 : tabs.map((tabItemProps, index) => {
4226
+ return React__namespace.default.createElement("div", { className: classNames__default.default("ui-flex ui-w-full ui-gap-xl", className) }, tabs === null || tabs === void 0 ? void 0 : tabs.map((tabItemProps, index) => {
4223
4227
  var _a;
4224
4228
  const itemProps = Object.assign({ index, onSelect: handleOnTabSelect, isSelected: innerSelectedIndex === index }, tabItemProps);
4225
4229
  return React__namespace.default.createElement(TabbarItem, Object.assign({ key: (_a = tabItemProps.dataTestId) !== null && _a !== void 0 ? _a : index }, itemProps));
4226
4230
  }));
4227
4231
  };
4228
4232
 
4233
+ const PageTitle = (props) => {
4234
+ const { as: Component = "h2", className } = props, rest = __rest(props, ["as", "className"]);
4235
+ return React__namespace.default.createElement(Component, Object.assign({}, rest, { className: classNames__default.default(
4236
+ "title-avenir ui-text-3xl ui-font-bold ui-antialiased",
4237
+ /**
4238
+ * Design calls for a specific line height. Let's see later
4239
+ * if we should include this in the titles sizing system.
4240
+ */
4241
+ "ui-leading-[1.2]",
4242
+ "ui-bg-gradient-to-br ui-from-blue-800 ui-to-blue-700 ui-bg-clip-text ui-text-transparent",
4243
+ className
4244
+ ) }));
4245
+ };
4246
+
4229
4247
  const PageHeader = ({ navigation, breadcrumbs, dataTestId, accessories, isPolling, title, contained, className, truncateBreadcrumbsAfter, banner }) => {
4248
+ var _a;
4230
4249
  const withContained = { "ui-max-w-3xl ui-m-auto": contained };
4250
+ const hasTabBar = Boolean((_a = navigation === null || navigation === void 0 ? void 0 : navigation.tabs) === null || _a === void 0 ? void 0 : _a.length);
4231
4251
  return React__namespace.default.createElement(
4232
- "div",
4233
- { "data-test-id": "page-header", className: classNames__default.default("ui-space-y-4 ui-bg-white", className, {
4234
- "ui-p-4": !contained,
4235
- "ui-w-full ui-py-4": contained
4236
- }) },
4237
- !!(breadcrumbs === null || breadcrumbs === void 0 ? void 0 : breadcrumbs.length) && React__namespace.default.createElement(
4238
- "div",
4239
- { className: classNames__default.default("ui-mb-4 ui-space-y-4", withContained) },
4240
- React__namespace.default.createElement(Breadcrumbs, { crumbs: breadcrumbs, truncateAfter: truncateBreadcrumbsAfter }),
4241
- React__namespace.default.createElement("div", { className: "ui-mb-4 ui-border-b ui-border-slate-100" })
4242
- ),
4243
- banner && React__namespace.default.createElement(
4244
- NotificationBanner,
4245
- { noBorder: banner.noBorder, color: banner.color, "data-test-id": `page-header-banner-${title}` },
4246
- React__namespace.default.createElement(
4247
- "div",
4248
- { className: "ui-flex ui-flex-col" },
4249
- banner.title && React__namespace.default.createElement(Text, { color: "current", type: "strong", text: banner.title }),
4250
- React__namespace.default.createElement(Text, { color: "current", text: banner.text.content, containsDangerousHtml: banner.text.isHTML })
4251
- )
4252
- ),
4252
+ React__namespace.default.Fragment,
4253
+ null,
4253
4254
  React__namespace.default.createElement(
4254
4255
  "div",
4255
- { className: classNames__default.default("ui-flex ui-flex-row ui-items-center ui-justify-between", withContained) },
4256
+ { "data-test-id": "page-header", className: classNames__default.default("ui-pt-xl", className, {
4257
+ /**
4258
+ * The tab bar should sit snugly against the bottom of the page header, but
4259
+ * this is the only exception. Other than that the page header should have
4260
+ * a bottom padding.
4261
+ */
4262
+ "ui-pb-l": !hasTabBar,
4263
+ "ui-px-xl": !contained,
4264
+ "ui-w-full": contained
4265
+ }) },
4266
+ banner && React__namespace.default.createElement(
4267
+ NotificationBanner,
4268
+ { noBorder: banner.noBorder, color: banner.color, "data-test-id": `page-header-banner-${title}`, className: "ui-mb-m" },
4269
+ React__namespace.default.createElement(
4270
+ "div",
4271
+ { className: "ui-flex ui-flex-col" },
4272
+ banner.title && React__namespace.default.createElement(Text, { color: "current", variant: "strong" }, banner.title),
4273
+ React__namespace.default.createElement(Text, { color: "current", containsDangerousHtml: banner.text.isHTML }, banner.text.content)
4274
+ )
4275
+ ),
4256
4276
  React__namespace.default.createElement(
4257
4277
  "div",
4258
- { className: "ui-flex ui-flex-row ui-items-center ui-space-x-3" },
4259
- React__namespace.default.createElement(Title, { "data-test-id": `${dataTestId}-title`, text: title }),
4260
- isPolling && React__namespace.default.createElement(LoadingIndicator, { asSpinner: true, className: "page-spinner", spinnerColor: "gray" })
4278
+ { className: classNames__default.default({ "ui-flex ui-flex-col": !contained }) },
4279
+ !!(breadcrumbs === null || breadcrumbs === void 0 ? void 0 : breadcrumbs.length) && React__namespace.default.createElement(
4280
+ "div",
4281
+ { className: classNames__default.default("ui-mb-m", withContained) },
4282
+ React__namespace.default.createElement(Breadcrumbs, { crumbs: breadcrumbs, truncateAfter: truncateBreadcrumbsAfter })
4283
+ ),
4284
+ React__namespace.default.createElement(
4285
+ "div",
4286
+ { className: classNames__default.default("ui-flex ui-flex-row ui-items-center ui-justify-between", withContained) },
4287
+ React__namespace.default.createElement(
4288
+ "div",
4289
+ { className: "ui-flex ui-flex-row ui-items-center ui-gap-xxs" },
4290
+ React__namespace.default.createElement(PageTitle, { "data-test-id": `${dataTestId}-title` }, title),
4291
+ isPolling && React__namespace.default.createElement(LoadingIndicator, { asSpinner: true, className: "page-spinner", spinnerColor: "gray" })
4292
+ ),
4293
+ accessories && React__namespace.default.createElement("div", { "data-test-id": "page-header-accessories" }, accessories)
4294
+ )
4261
4295
  ),
4262
- accessories && React__namespace.default.createElement("div", { "data-test-id": "page-header-accessories" }, accessories)
4296
+ navigation && React__namespace.default.createElement(Tabbar, Object.assign({}, navigation, { className: classNames__default.default(navigation.className, withContained) }))
4263
4297
  ),
4264
- navigation && React__namespace.default.createElement(Tabbar, Object.assign({}, navigation, { withoutPadding: true, className: classNames__default.default(navigation.className, withContained) }))
4298
+ React__namespace.default.createElement(Divider, { version: "v2" })
4265
4299
  );
4266
4300
  };
4267
4301
 
@@ -4271,14 +4305,14 @@ const CRUDPage = ({ submitButtonProps, cancelButtonProps, className, children, i
4271
4305
  const cancelButton = cancelButtonProps && React__namespace.default.createElement(TertiaryButton, Object.assign({ "data-test-id": "cancel-button", key: "cancel-button", role: BUTTON_ROLES.SECONDARY }, cancelButtonProps));
4272
4306
  let pageHeader;
4273
4307
  if (title) {
4274
- pageHeader = React__namespace.default.createElement(
4308
+ pageHeader = React__namespace.default.createElement(PageHeader, { banner: null, title: React__namespace.default.createElement(
4275
4309
  "div",
4276
- { className: "ui-align-center ui-mx-auto ui-mt-8 ui-flex ui-w-full ui-max-w-3xl ui-flex-row ui-justify-start" },
4277
- title.icon && React__namespace.default.createElement("img", { id: "title-icon", src: title.icon, className: "ui-mr-4 ui-h-11 ui-w-11", alt: "title icon" }),
4278
- React__namespace.default.createElement(Title, { text: title.text, type: "lg" })
4279
- );
4310
+ { className: "ui-flex ui-flex-nowrap ui-items-center ui-gap-m" },
4311
+ title.icon && React__namespace.default.createElement("img", { id: "title-icon", src: title.icon, className: "ui-h-9 ui-w-9", alt: "title icon" }),
4312
+ React__namespace.default.createElement(PageTitle, null, title.text)
4313
+ ) });
4280
4314
  } else {
4281
- pageHeader = React__namespace.default.createElement(PageHeader, Object.assign({ contained: true }, header));
4315
+ pageHeader = React__namespace.default.createElement(PageHeader, Object.assign({}, header));
4282
4316
  }
4283
4317
  return React__namespace.default.createElement(
4284
4318
  "div",
@@ -4287,18 +4321,24 @@ const CRUDPage = ({ submitButtonProps, cancelButtonProps, className, children, i
4287
4321
  "div",
4288
4322
  { className: classNames__default.default(mergedClasses, "ui-relative ui-overflow-y-hidden", "cweb-crud-page-loading-container"), style: { height: "90vh" } },
4289
4323
  React__namespace.default.createElement("div", { className: "ui-align-center ui-flex ui-flex-row ui-justify-start" }, pageHeader),
4324
+ React__namespace.default.createElement(Divider, { version: "v2" }),
4290
4325
  React__namespace.default.createElement(LoadingIndicator, { className: classNames__default.default("crud-page-loader", "ui-absolute ui-bottom-0 ui-left-0 ui-right-0 ui-top-0 ui-m-auto ui-h-12 ui-w-12"), asModal: false })
4291
4326
  ),
4292
4327
  !isLoading && React__namespace.default.createElement(
4293
4328
  "div",
4294
4329
  { className: mergedClasses, "data-test-id": dataTestId },
4295
4330
  React__namespace.default.createElement("div", { className: "ui-align-center ui-flex ui-flex-row ui-justify-start" }, pageHeader),
4331
+ React__namespace.default.createElement(Divider, { version: "v2" }),
4296
4332
  React__namespace.default.createElement(
4297
4333
  "div",
4298
- { className: classNames__default.default("cweb-crud-page-form-container", "lg ui-mx-auto ui-mt-4 ui-max-w-3xl ui-rounded ui-bg-white ui-p-6") },
4299
- steps && React__namespace.default.createElement(Steps, { className: "ui-mb-4", orderedStepTitles: steps.titles, currentStep: steps.currentStep, localization: steps.localization }),
4300
- children,
4301
- React__namespace.default.createElement(Line, { left: [submitButton, cancelButton], className: classNames__default.default("cweb-crud-page-button-line", "ui-mt-4 ui-border-t ui-border-solid ui-border-color-divider ui-pt-4") })
4334
+ { className: "ui-flex ui-justify-center" },
4335
+ React__namespace.default.createElement(
4336
+ "div",
4337
+ { className: classNames__default.default("cweb-crud-page-form-container", "ui-mt-xl ui-w-full ui-max-w-3xl ui-rounded ui-bg-white ui-p-6") },
4338
+ steps && React__namespace.default.createElement(Steps, { className: "ui-mb-4", orderedStepTitles: steps.titles, currentStep: steps.currentStep, localization: steps.localization }),
4339
+ children,
4340
+ React__namespace.default.createElement(Line, { left: [submitButton, cancelButton], className: classNames__default.default("cweb-crud-page-button-line", "ui-mt-4 ui-border-t ui-border-solid ui-border-color-divider ui-pt-4") })
4341
+ )
4302
4342
  )
4303
4343
  )
4304
4344
  );
@@ -5431,7 +5471,7 @@ const FullPageModalHeader = ({ primaryButtonProps, actions, title }) => {
5431
5471
  return React__namespace.default.createElement(
5432
5472
  "div",
5433
5473
  { className: "ui-flex ui-h-19 ui-flex-row ui-items-center ui-justify-between ui-bg-white ui-px-6" },
5434
- React__namespace.default.createElement(Title, { text: title }),
5474
+ React__namespace.default.createElement(PageTitle, null, title),
5435
5475
  primaryButtonProps && !actions && React__namespace.default.createElement(PrimaryButton, Object.assign({ "data-test-id": "modal-primary-button" }, primaryButtonProps)),
5436
5476
  actions && React__namespace.default.createElement("div", null, actions)
5437
5477
  );