hazo_auth 10.6.0 → 10.7.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.
package/README.md CHANGED
@@ -1656,7 +1656,7 @@ logo_height = 32 # Logo height in pixels
1656
1656
  company_name = My Company # Company name (links to home)
1657
1657
  home_path = / # URL for logo and company name link
1658
1658
  home_label = Home # Label for home link
1659
- show_home_link = true # Show "Home" link on right side
1659
+ show_home_link = true # Show "Home" link (only used when no logo/company_name is set — see below)
1660
1660
  background_color = # Custom background (optional)
1661
1661
  text_color = # Custom text color (optional)
1662
1662
  height = 64 # Navbar height in pixels
@@ -1664,6 +1664,10 @@ height = 64 # Navbar height in pixels
1664
1664
 
1665
1665
  The navbar provides consistent branding across authentication pages with your company logo, name, and optional home link. It automatically vertically centers auth content when enabled.
1666
1666
 
1667
+ **Home link behavior:** the standalone "Home" link and your brand (logo/company name) never both render — the brand link already goes home.
1668
+ - `logo_path` or `company_name` set → the brand renders on the left as a link to `home_path`; the separate "Home" link is hidden, regardless of `show_home_link`.
1669
+ - Neither set → the "Home" link (icon + label) renders on the **left** instead, as long as `show_home_link = true`.
1670
+
1667
1671
  **Zero-config usage (recommended):**
1668
1672
  ```typescript
1669
1673
  // app/hazo_auth/login/page.tsx
@@ -4,10 +4,22 @@ import { type ButtonPaletteOverrides } from "../shared/config/layout_customizati
4
4
  export type CreateFirmLayoutProps = {
5
5
  /** Image source for the left panel */
6
6
  image_src: string | StaticImageData;
7
+ /**
8
+ * Capitalised singular noun for the organisation entity (e.g. "Firm",
9
+ * "Business", "Company"). Drives the default heading, field labels, button
10
+ * and banner text so a consumer can re-label the whole page from one value.
11
+ */
12
+ keyword?: string;
13
+ /** Lowercase form of {@link keyword} used mid-sentence (e.g. "firm"). */
14
+ keyword_lower?: string;
15
+ /** Capitalised verb for the primary action (e.g. "Create", "Setup"). */
16
+ verb?: string;
7
17
  /** Alt text for the image */
8
18
  image_alt?: string;
9
19
  /** Background color for the image panel */
10
20
  image_background_color?: string;
21
+ /** Banner body text shown in the info callout */
22
+ banner_body?: string;
11
23
  /** Page heading */
12
24
  heading?: string;
13
25
  /** Page sub-heading */
@@ -40,6 +52,6 @@ export type CreateFirmLayoutProps = {
40
52
  error: (message: string, data?: Record<string, unknown>) => void;
41
53
  };
42
54
  };
43
- export default function CreateFirmLayout({ image_src, image_alt, image_background_color, heading, sub_heading, firm_name_label, firm_name_placeholder, org_structure_label, org_structure_placeholder, default_org_structure, submit_button_label, success_message, redirect_route, apiBasePath, onSuccess, button_colors, logger, }: CreateFirmLayoutProps): React.JSX.Element;
55
+ export default function CreateFirmLayout({ image_src, keyword, keyword_lower, verb, image_alt, image_background_color, banner_body, heading, sub_heading, firm_name_label, firm_name_placeholder, org_structure_label, org_structure_placeholder, default_org_structure, submit_button_label, success_message, redirect_route, apiBasePath, onSuccess, button_colors, logger, }: CreateFirmLayoutProps): React.JSX.Element;
44
56
  export { CreateFirmLayout };
45
57
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/create_firm/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAOlD,OAAO,EACL,KAAK,sBAAsB,EAC5B,MAAM,uCAAuC,CAAC;AAQ/C,MAAM,MAAM,qBAAqB,GAAG;IAClC,sCAAsC;IACtC,SAAS,EAAE,MAAM,GAAG,eAAe,CAAC;IACpC,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,mBAAmB;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oCAAoC;IACpC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0CAA0C;IAC1C,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,sCAAsC;IACtC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,8BAA8B;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,6BAA6B;IAC7B,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,2BAA2B;IAC3B,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QAChE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;KAClE,CAAC;CACH,CAAC;AAGF,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,SAAS,EACT,SAA8B,EAC9B,sBAAkC,EAClC,OAA4B,EAC5B,WAAuD,EACvD,eAA6B,EAC7B,qBAA8C,EAC9C,mBAA8C,EAC9C,yBAA6D,EAC7D,qBAAsC,EACtC,mBAAmC,EACnC,eAA4D,EAC5D,cAAoB,EACpB,WAAW,EACX,SAAS,EACT,aAAa,EACb,MAAM,GACP,EAAE,qBAAqB,qBA2JvB;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/create_firm/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAOlD,OAAO,EACL,KAAK,sBAAsB,EAC5B,MAAM,uCAAuC,CAAC;AAQ/C,MAAM,MAAM,qBAAqB,GAAG;IAClC,sCAAsC;IACtC,SAAS,EAAE,MAAM,GAAG,eAAe,CAAC;IACpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oCAAoC;IACpC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0CAA0C;IAC1C,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,sCAAsC;IACtC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,8BAA8B;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,6BAA6B;IAC7B,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,2BAA2B;IAC3B,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QAChE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;KAClE,CAAC;CACH,CAAC;AAGF,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,SAAS,EACT,OAAgB,EAChB,aAAsB,EACtB,IAAe,EACf,SAA2C,EAC3C,sBAAkC,EAClC,WAAyK,EACzK,OAAmC,EACnC,WAAuD,EACvD,eAAmC,EACnC,qBAA0D,EAC1D,mBAA8C,EAC9C,yBAA6D,EAC7D,qBAAsC,EACtC,mBAA0C,EAC1C,eAAwE,EACxE,cAAoB,EACpB,WAAW,EACX,SAAS,EACT,aAAa,EACb,MAAM,GACP,EAAE,qBAAqB,qBAuJvB;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -11,7 +11,7 @@ import { CheckCircle, Building2 } from "lucide-react";
11
11
  import { use_create_firm_form, } from "./hooks/use_create_firm_form.js";
12
12
  import { useHazoAuthConfig } from "../../../contexts/hazo_auth_provider.js";
13
13
  // section: component
14
- export default function CreateFirmLayout({ image_src, image_alt = "Create your firm", image_background_color = "#f1f5f9", heading = "Create Your Firm", sub_heading = "Set up your organisation to get started", firm_name_label = "Firm Name", firm_name_placeholder = "Enter your firm name", org_structure_label = "Organisation Structure", org_structure_placeholder = "e.g., Headquarters, Head Office", default_org_structure = "Headquarters", submit_button_label = "Create Firm", success_message = "Your firm has been created successfully!", redirect_route = "/", apiBasePath, onSuccess, button_colors, logger, }) {
14
+ export default function CreateFirmLayout({ image_src, keyword = "Firm", keyword_lower = "firm", verb = "Create", image_alt = `${verb} your ${keyword_lower}`, image_background_color = "#f1f5f9", banner_body = `${verb} your ${keyword_lower} to start using the application. You'll become the administrator of your ${keyword_lower} and can invite team members later.`, heading = `${verb} Your ${keyword}`, sub_heading = "Set up your organisation to get started", firm_name_label = `${keyword} Name`, firm_name_placeholder = `Enter your ${keyword_lower} name`, org_structure_label = "Organisation Structure", org_structure_placeholder = "e.g., Headquarters, Head Office", default_org_structure = "Headquarters", submit_button_label = `${verb} ${keyword}`, success_message = `Your ${keyword_lower} has been created successfully!`, redirect_route = "/", apiBasePath, onSuccess, button_colors, logger, }) {
15
15
  const { apiBasePath: contextApiBasePath } = useHazoAuthConfig();
16
16
  const resolvedApiBasePath = apiBasePath || contextApiBasePath;
17
17
  const form = use_create_firm_form({
@@ -39,7 +39,7 @@ export default function CreateFirmLayout({ image_src, image_alt = "Create your f
39
39
  if (form.isSuccess) {
40
40
  return (_jsx(TwoColumnAuthLayout, { imageSrc: image_src, imageAlt: image_alt, imageBackgroundColor: image_background_color, formContent: _jsxs(_Fragment, { children: [_jsx(FormHeader, { heading: heading, subHeading: sub_heading }), _jsxs("div", { className: "cls_create_firm_layout_success flex flex-col items-center justify-center gap-4 p-8 text-center", children: [_jsx(CheckCircle, { className: "cls_create_firm_layout_success_icon h-16 w-16 text-green-600", "aria-hidden": "true" }), _jsx("p", { className: "cls_create_firm_layout_success_message text-lg font-medium text-slate-900", children: success_message }), _jsx("p", { className: "cls_create_firm_layout_redirect_message text-sm text-muted-foreground", children: "Redirecting you to the application..." })] })] }) }));
41
41
  }
42
- return (_jsx(TwoColumnAuthLayout, { imageSrc: image_src, imageAlt: image_alt, imageBackgroundColor: image_background_color, formContent: _jsxs(_Fragment, { children: [_jsx(FormHeader, { heading: heading, subHeading: sub_heading }), _jsxs("div", { className: "cls_create_firm_layout_info mb-6 flex items-start gap-3 rounded-lg border border-blue-200 bg-blue-50 p-4", children: [_jsx(Building2, { className: "mt-0.5 h-5 w-5 flex-shrink-0 text-blue-600" }), _jsxs("div", { className: "text-sm text-blue-800", children: [_jsx("p", { className: "font-medium", children: "Welcome!" }), _jsx("p", { children: "Create your firm to start using the application. You'll become the administrator of your firm and can invite team members later." })] })] }), _jsxs("form", { className: "cls_create_firm_layout_form_fields flex flex-col gap-5", onSubmit: form.handleSubmit, "aria-label": "Create firm form", children: [renderFields(form), form.errors.form && (_jsx("div", { className: "cls_create_firm_layout_form_error rounded-md bg-red-50 p-3 text-sm text-red-600", children: form.errors.form })), form.hasAutofillPreview && !form.values.firm_name && (_jsx("div", { className: "cls_create_firm_layout_autofill_hint rounded-md bg-amber-50 p-3 text-sm text-amber-700", children: "Click in the firm name field to confirm the autofilled value" })), _jsx(FormActionButtons, { submitLabel: submit_button_label, buttonPalette: resolvedButtonPalette, isSubmitDisabled: form.isSubmitDisabled, submitAriaLabel: "Create your firm", hideCancel: true })] })] }) }));
42
+ return (_jsx(TwoColumnAuthLayout, { imageSrc: image_src, imageAlt: image_alt, imageBackgroundColor: image_background_color, formContent: _jsxs(_Fragment, { children: [_jsx(FormHeader, { heading: heading, subHeading: sub_heading }), _jsxs("div", { className: "cls_create_firm_layout_info mb-6 flex items-start gap-3 rounded-lg border border-blue-200 bg-blue-50 p-4", children: [_jsx(Building2, { className: "mt-0.5 h-5 w-5 flex-shrink-0 text-blue-600" }), _jsxs("div", { className: "text-sm text-blue-800", children: [_jsx("p", { className: "font-medium", children: "Welcome!" }), _jsx("p", { children: banner_body })] })] }), _jsxs("form", { className: "cls_create_firm_layout_form_fields flex flex-col gap-5", onSubmit: form.handleSubmit, "aria-label": `${verb} ${keyword_lower} form`, children: [renderFields(form), form.errors.form && (_jsx("div", { className: "cls_create_firm_layout_form_error rounded-md bg-red-50 p-3 text-sm text-red-600", children: form.errors.form })), form.hasAutofillPreview && !form.values.firm_name && (_jsxs("div", { className: "cls_create_firm_layout_autofill_hint rounded-md bg-amber-50 p-3 text-sm text-amber-700", children: ["Click in the ", keyword_lower, " name field to confirm the autofilled value"] })), _jsx(FormActionButtons, { submitLabel: submit_button_label, buttonPalette: resolvedButtonPalette, isSubmitDisabled: form.isSubmitDisabled, submitAriaLabel: image_alt, hideCancel: true })] })] }) }));
43
43
  }
44
44
  // section: exports
45
45
  export { CreateFirmLayout };
@@ -36,7 +36,7 @@ export const resolveLoginLabels = (overrides) => resolveLabels(LOGIN_LABEL_DEFAU
36
36
  const LOGIN_BUTTON_PALETTE_DEFAULTS = {
37
37
  submitBackground: "#0f172a",
38
38
  submitText: "#ffffff",
39
- cancelBorder: "#cbd5f5",
40
- cancelText: "#0f172a",
39
+ cancelBorder: "hsl(var(--border))",
40
+ cancelText: "hsl(var(--foreground))",
41
41
  };
42
42
  export const resolveLoginButtonPalette = (overrides) => resolveButtonPalette(LOGIN_BUTTON_PALETTE_DEFAULTS, overrides);
@@ -54,8 +54,8 @@ export const resolveRegisterLabels = (overrides) => resolveLabels(REGISTER_LABEL
54
54
  const REGISTER_BUTTON_PALETTE_DEFAULTS = {
55
55
  submitBackground: "#0f172a",
56
56
  submitText: "#ffffff",
57
- cancelBorder: "#cbd5f5",
58
- cancelText: "#0f172a",
57
+ cancelBorder: "hsl(var(--border))",
58
+ cancelText: "hsl(var(--foreground))",
59
59
  };
60
60
  export const resolveRegisterButtonPalette = (overrides) => resolveButtonPalette(REGISTER_BUTTON_PALETTE_DEFAULTS, overrides);
61
61
  // section: password_rules
@@ -1 +1 @@
1
- {"version":3,"file":"auth_navbar.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/auth_navbar.tsx"],"names":[],"mappings":"AAWA,MAAM,MAAM,eAAe,GAAG;IAC5B,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qBAAqB;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8BAA8B;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wBAAwB;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAGF,wBAAgB,UAAU,CAAC,EACzB,SAAc,EACd,UAAe,EACf,WAAgB,EAChB,YAAiB,EACjB,SAAe,EACf,UAAmB,EACnB,cAAqB,EACrB,gBAAgB,EAChB,UAAU,EACV,MAAW,EACX,SAAS,GACV,EAAE,eAAe,+BAuDjB"}
1
+ {"version":3,"file":"auth_navbar.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/auth_navbar.tsx"],"names":[],"mappings":"AAWA,MAAM,MAAM,eAAe,GAAG;IAC5B,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qBAAqB;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8BAA8B;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wBAAwB;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAGF,wBAAgB,UAAU,CAAC,EACzB,SAAc,EACd,UAAe,EACf,WAAgB,EAChB,YAAiB,EACjB,SAAe,EACf,UAAmB,EACnB,cAAqB,EACrB,gBAAgB,EAChB,UAAU,EACV,MAAW,EACX,SAAS,GACV,EAAE,eAAe,+BAoDjB"}
@@ -11,6 +11,7 @@ import { cn } from "../../../../lib/utils.js";
11
11
  export function AuthNavbar({ logo_path = "", logo_width = 28, logo_height = 28, company_name = "", home_path = "/", home_label = "Home", show_home_link = true, background_color, text_color, height = 40, className, }) {
12
12
  // Only show logo if logo_path is configured (non-empty)
13
13
  const showLogo = logo_path !== "";
14
+ const hasBrand = showLogo || company_name !== "";
14
15
  const navStyle = Object.assign(Object.assign({ height: `${height}px` }, (background_color && { backgroundColor: background_color })), (text_color && { color: text_color }));
15
- return (_jsxs("nav", { className: cn("cls_auth_navbar flex w-full items-center justify-between border-b border-border/40 bg-background/95 px-4 backdrop-blur supports-[backdrop-filter]:bg-background/60", className), style: navStyle, "aria-label": "Authentication page navigation", children: [_jsx("div", { className: "cls_auth_navbar_brand flex items-center gap-3", children: (showLogo || company_name) && (_jsxs(Link, { href: home_path, className: "cls_auth_navbar_logo_link flex items-center gap-3", children: [showLogo && (_jsx(Image, { src: logo_path, alt: company_name ? `${company_name} logo` : "Logo", width: logo_width, height: logo_height, className: "cls_auth_navbar_logo object-contain" })), company_name && (_jsx("span", { className: "cls_auth_navbar_company_name text-lg font-semibold text-foreground", children: company_name }))] })) }), show_home_link && (_jsx("div", { className: "cls_auth_navbar_links flex items-center gap-4", children: _jsxs(Link, { href: home_path, className: "cls_auth_navbar_home_link flex items-center gap-2 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground", "aria-label": `Navigate to ${home_label}`, children: [_jsx(Home, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: home_label })] }) }))] }));
16
+ return (_jsx("nav", { className: cn("cls_auth_navbar flex w-full items-center justify-between border-b border-border/40 bg-background/95 px-4 backdrop-blur supports-[backdrop-filter]:bg-background/60", className), style: navStyle, "aria-label": "Authentication page navigation", children: _jsxs("div", { className: "cls_auth_navbar_brand flex items-center gap-3", children: [hasBrand && (_jsxs(Link, { href: home_path, className: "cls_auth_navbar_logo_link flex items-center gap-3", children: [showLogo && (_jsx(Image, { src: logo_path, alt: company_name ? `${company_name} logo` : "Logo", width: logo_width, height: logo_height, className: "cls_auth_navbar_logo object-contain" })), company_name && (_jsx("span", { className: "cls_auth_navbar_company_name text-lg font-semibold text-foreground", children: company_name }))] })), !hasBrand && show_home_link && (_jsxs(Link, { href: home_path, className: "cls_auth_navbar_home_link flex items-center gap-2 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground", "aria-label": `Navigate to ${home_label}`, children: [_jsx(Home, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: home_label })] }))] }) }));
16
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"create_firm.d.ts","sourceRoot":"","sources":["../../src/page_components/create_firm.tsx"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAQrB,MAAM,MAAM,mBAAmB,GAAG;IAChC,iCAAiC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAsDF,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EAAE,aAAa,EAAE,GAAE,mBAAwB,+BAsBjF;AAGD,OAAO,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"create_firm.d.ts","sourceRoot":"","sources":["../../src/page_components/create_firm.tsx"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAQrB,MAAM,MAAM,mBAAmB,GAAG;IAChC,iCAAiC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAyCF,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EAAE,aAAa,EAAE,GAAE,mBAAwB,+BAyBjF;AAGD,OAAO,EAAE,cAAc,EAAE,CAAC"}
@@ -7,23 +7,36 @@ import CreateFirmLayout from "../components/layouts/create_firm/index.js";
7
7
  import { AuthPageShell } from "../components/layouts/shared/components/auth_page_shell.js";
8
8
  import { get_config_value } from "../lib/config/config_loader.server.js";
9
9
  // section: config_loader
10
+ const CREATE_FIRM_SECTION = "hazo_auth__create_firm";
11
+ // Reads an optional label override: returns the configured string, or undefined
12
+ // when the key is absent/empty so the layout can derive it from `keyword`/`verb`.
13
+ function get_optional_config_value(key) {
14
+ return get_config_value(CREATE_FIRM_SECTION, key, "") || undefined;
15
+ }
10
16
  function get_create_firm_config() {
11
17
  return {
12
- image_src: get_config_value("hazo_auth__create_firm", "image_src", "/hazo_auth/images/new_firm_default.jpg"),
13
- heading: get_config_value("hazo_auth__create_firm", "heading", "Create Your Firm"),
14
- sub_heading: get_config_value("hazo_auth__create_firm", "sub_heading", "Set up your organisation to get started"),
15
- firm_name_label: get_config_value("hazo_auth__create_firm", "firm_name_label", "Firm Name"),
16
- org_structure_label: get_config_value("hazo_auth__create_firm", "org_structure_label", "Organisation Structure"),
17
- org_structure_default: get_config_value("hazo_auth__create_firm", "org_structure_default", "Headquarters"),
18
- submit_button_label: get_config_value("hazo_auth__create_firm", "submit_button_label", "Create Firm"),
19
- success_message: get_config_value("hazo_auth__create_firm", "success_message", "Your firm has been created successfully!"),
20
- redirect_route: get_config_value("hazo_auth__create_firm", "redirect_route", "/"),
18
+ // Configurable entity keyword + action verb. These drive every default
19
+ // label in the layout, so a consumer can re-brand the whole page (e.g.
20
+ // "Business"/"Setup") from three config values.
21
+ keyword: get_config_value(CREATE_FIRM_SECTION, "keyword", "Firm"),
22
+ keyword_lower: get_config_value(CREATE_FIRM_SECTION, "keyword_lower", "firm"),
23
+ verb: get_config_value(CREATE_FIRM_SECTION, "verb", "Create"),
24
+ image_src: get_config_value(CREATE_FIRM_SECTION, "image_src", "/hazo_auth/images/new_firm_default.jpg"),
25
+ // Explicit per-label overrides (undefined keyword-derived default).
26
+ heading: get_optional_config_value("heading"),
27
+ sub_heading: get_optional_config_value("sub_heading"),
28
+ firm_name_label: get_optional_config_value("firm_name_label"),
29
+ org_structure_label: get_optional_config_value("org_structure_label"),
30
+ org_structure_default: get_config_value(CREATE_FIRM_SECTION, "org_structure_default", "Headquarters"),
31
+ submit_button_label: get_optional_config_value("submit_button_label"),
32
+ success_message: get_optional_config_value("success_message"),
33
+ redirect_route: get_config_value(CREATE_FIRM_SECTION, "redirect_route", "/"),
21
34
  };
22
35
  }
23
36
  // section: component
24
37
  export default function CreateFirmPage({ disableNavbar } = {}) {
25
38
  const config = get_create_firm_config();
26
- const layoutContent = (_jsx(CreateFirmLayout, { image_src: config.image_src, heading: config.heading, sub_heading: config.sub_heading, firm_name_label: config.firm_name_label, org_structure_label: config.org_structure_label, default_org_structure: config.org_structure_default, submit_button_label: config.submit_button_label, success_message: config.success_message, redirect_route: config.redirect_route }));
39
+ const layoutContent = (_jsx(CreateFirmLayout, { image_src: config.image_src, keyword: config.keyword, keyword_lower: config.keyword_lower, verb: config.verb, heading: config.heading, sub_heading: config.sub_heading, firm_name_label: config.firm_name_label, org_structure_label: config.org_structure_label, default_org_structure: config.org_structure_default, submit_button_label: config.submit_button_label, success_message: config.success_message, redirect_route: config.redirect_route }));
27
40
  if (disableNavbar) {
28
41
  return layoutContent;
29
42
  }
@@ -26,7 +26,7 @@ export declare function GET(request: NextRequest): Promise<NextResponse<{
26
26
  profile_source: {} | null;
27
27
  user_type: string | null;
28
28
  app_user_data: Record<string, unknown> | null;
29
- legal_acceptance_status: "current" | "outdated" | "none";
29
+ legal_acceptance_status: "current" | "none" | "outdated";
30
30
  }[];
31
31
  }>>;
32
32
  /**
@@ -33,6 +33,13 @@ export type LoginPageProps = {
33
33
  email?: string;
34
34
  password?: string;
35
35
  };
36
+ /**
37
+ * Force-disable the package navbar for this page, so a consuming app can
38
+ * render its own navbar/logo around the login form instead.
39
+ * Only applies in `layout: "two_column"` mode (ignored in `form_only`, which
40
+ * never renders AuthPageShell / the navbar anyway).
41
+ */
42
+ disableNavbar?: boolean;
36
43
  };
37
44
  /**
38
45
  * Zero-config LoginPage server component
@@ -57,6 +64,6 @@ export type LoginPageProps = {
57
64
  * @param props - Optional visual customization props
58
65
  * @returns Server-rendered login page
59
66
  */
60
- export default function LoginPage({ image_src, image_alt, image_background_color, layout, default_values, }?: LoginPageProps): import("react").JSX.Element;
67
+ export default function LoginPage({ image_src, image_alt, image_background_color, layout, default_values, disableNavbar, }?: LoginPageProps): import("react").JSX.Element;
61
68
  export { LoginPage };
62
69
  //# sourceMappingURL=login.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/server_pages/login.tsx"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAUrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAErC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC;IACpC,+EAA+E;IAC/E,cAAc,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxD,CAAC;AAGF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAChC,SAAS,EACT,SAAS,EACT,sBAAsB,EACtB,MAAqB,EACrB,cAAc,GACf,GAAE,cAAmB,+BAuErB;AAGD,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/server_pages/login.tsx"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAUrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAErC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC;IACpC,+EAA+E;IAC/E,cAAc,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAEvD;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAGF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAChC,SAAS,EACT,SAAS,EACT,sBAAsB,EACtB,MAAqB,EACrB,cAAc,EACd,aAAqB,GACtB,GAAE,cAAmB,+BAuErB;AAGD,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -33,7 +33,7 @@ import { FloatingHomeLink } from "../components/layouts/shared/components/floati
33
33
  * @param props - Optional visual customization props
34
34
  * @returns Server-rendered login page
35
35
  */
36
- export default function LoginPage({ image_src, image_alt, image_background_color, layout = "two_column", default_values, } = {}) {
36
+ export default function LoginPage({ image_src, image_alt, image_background_color, layout = "two_column", default_values, disableNavbar = false, } = {}) {
37
37
  // Load configuration from INI file (with defaults including asset images)
38
38
  const config = get_login_config();
39
39
  // Resolve strings for heading/subheading/ctaText
@@ -69,7 +69,7 @@ export default function LoginPage({ image_src, image_alt, image_background_color
69
69
  const navbar = get_navbar_config();
70
70
  return (_jsxs(_Fragment, { children: [navbar.show_home_link && (_jsx(FloatingHomeLink, { path: navbar.home_path, label: navbar.home_label })), wrapper] }));
71
71
  }
72
- return _jsx(AuthPageShell, { children: wrapper });
72
+ return _jsx(AuthPageShell, { disableNavbar: disableNavbar, children: wrapper });
73
73
  }
74
74
  // Named export for direct imports
75
75
  export { LoginPage };
@@ -22,6 +22,13 @@ export type RegisterPageProps = {
22
22
  * TwoColumnAuthLayout so the consumer's brand chrome can wrap the form.
23
23
  */
24
24
  layout?: "two_column" | "form_only";
25
+ /**
26
+ * Force-disable the package navbar for this page, so a consuming app can
27
+ * render its own navbar/logo around the registration form instead.
28
+ * Only applies in `layout: "two_column"` mode (ignored in `form_only`, which
29
+ * never renders AuthPageShell / the navbar anyway).
30
+ */
31
+ disableNavbar?: boolean;
25
32
  };
26
33
  /**
27
34
  * Zero-config RegisterPage server component
@@ -48,6 +55,6 @@ export type RegisterPageProps = {
48
55
  * @param props - Optional visual customization props
49
56
  * @returns Server-rendered register page
50
57
  */
51
- export default function RegisterPage({ image_src, image_alt, image_background_color, layout, }?: RegisterPageProps): import("react").JSX.Element;
58
+ export default function RegisterPage({ image_src, image_alt, image_background_color, layout, disableNavbar, }?: RegisterPageProps): import("react").JSX.Element;
52
59
  export { RegisterPage };
53
60
  //# sourceMappingURL=register.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/server_pages/register.tsx"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAUrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAErC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;;;OAIG;IACH,MAAM,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC;CACrC,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,SAAS,EACT,SAAS,EACT,sBAAsB,EACtB,MAAqB,GACtB,GAAE,iBAAsB,+BA2DxB;AAGD,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/server_pages/register.tsx"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAUrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAErC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;;;OAIG;IACH,MAAM,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC;IAEpC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,SAAS,EACT,SAAS,EACT,sBAAsB,EACtB,MAAqB,EACrB,aAAqB,GACtB,GAAE,iBAAsB,+BA2DxB;AAGD,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -35,7 +35,7 @@ import { FloatingHomeLink } from "../components/layouts/shared/components/floati
35
35
  * @param props - Optional visual customization props
36
36
  * @returns Server-rendered register page
37
37
  */
38
- export default function RegisterPage({ image_src, image_alt, image_background_color, layout = "two_column", } = {}) {
38
+ export default function RegisterPage({ image_src, image_alt, image_background_color, layout = "two_column", disableNavbar = false, } = {}) {
39
39
  // Load configuration from INI file (with defaults including asset images)
40
40
  const config = get_register_config();
41
41
  const strings = readStrings();
@@ -63,7 +63,7 @@ export default function RegisterPage({ image_src, image_alt, image_background_co
63
63
  const navbar = get_navbar_config();
64
64
  return (_jsxs(_Fragment, { children: [navbar.show_home_link && (_jsx(FloatingHomeLink, { path: navbar.home_path, label: navbar.home_label })), wrapper] }));
65
65
  }
66
- return _jsx(AuthPageShell, { children: wrapper });
66
+ return _jsx(AuthPageShell, { disableNavbar: disableNavbar, children: wrapper });
67
67
  }
68
68
  // Named export for direct imports
69
69
  export { RegisterPage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hazo_auth",
3
- "version": "10.6.0",
3
+ "version": "10.7.1",
4
4
  "description": "Zero-config authentication UI components for Next.js with RBAC, OAuth, scope-based multi-tenancy, and invitations",
5
5
  "keywords": [
6
6
  "authentication",