@motor-hero/ui-kit 0.37.0 → 0.37.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motor-hero/ui-kit",
3
- "version": "0.37.0",
3
+ "version": "0.37.2",
4
4
  "description": "Componentes React reutilizáveis para o ecossistema MotorHero — shadcn/ui + Tailwind CSS v4",
5
5
  "author": "MotorHero",
6
6
  "license": "UNLICENSED",
@@ -31,7 +31,7 @@ export function FormField({ label, htmlFor, error, required, children, className
31
31
  <div className={`space-y-2 ${className ?? ""}`}>
32
32
  <label
33
33
  htmlFor={htmlFor}
34
- className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
34
+ className="block text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
35
35
  >
36
36
  {label}
37
37
  {required && <span className="ml-1 text-destructive">*</span>}
@@ -3,17 +3,43 @@ import { useState } from "react"
3
3
  export type UseCompanySubdomainOptions = {
4
4
  enableOverride?: boolean
5
5
  overrideStorageKey?: string
6
+ /**
7
+ * Host labels that are *not* tenants. A product whose default host carries
8
+ * a label of its own (`app.example.com`, `admin.example.com`) must list it
9
+ * here, or that label is read as a tenant slug and sent downstream as one.
10
+ *
11
+ * Added to the built-in `www`; `localhost` is always excluded structurally.
12
+ * Case-insensitive.
13
+ */
14
+ reservedSubdomains?: string[]
6
15
  }
7
16
 
8
17
  export type UseCompanySubdomainResult = {
9
18
  subdomain: string | undefined
10
19
  }
11
20
 
12
- export function getSubdomain(hostname: string): string | undefined {
21
+ const ALWAYS_RESERVED = ["www", "localhost"]
22
+
23
+ /**
24
+ * The tenant slug in a hostname, or `undefined` when there is none.
25
+ *
26
+ * The first label is only a tenant if it isn't reserved. Callers whose
27
+ * default host is `app.<domain>` must pass `["app"]` (plus any sibling
28
+ * surfaces like `admin`), otherwise visiting the default host yields the
29
+ * literal `"app"` as if it were a customer.
30
+ */
31
+ export function getSubdomain(
32
+ hostname: string,
33
+ reservedSubdomains: string[] = [],
34
+ ): string | undefined {
13
35
  const labels = hostname.split(".")
14
36
  if (labels.length < 2) return undefined
15
37
  const first = labels[0]
16
- if (!first || first === "www" || first === "localhost") return undefined
38
+ if (!first) return undefined
39
+ const reserved = [...ALWAYS_RESERVED, ...reservedSubdomains].map((label) =>
40
+ label.toLowerCase(),
41
+ )
42
+ if (reserved.includes(first.toLowerCase())) return undefined
17
43
  return first
18
44
  }
19
45
 
@@ -35,8 +61,11 @@ function resolveOverride(storageKey: string): string | undefined {
35
61
  export function useCompanySubdomain(
36
62
  opts: UseCompanySubdomainOptions = {},
37
63
  ): UseCompanySubdomainResult {
38
- const { enableOverride = false, overrideStorageKey = "company-subdomain" } =
39
- opts
64
+ const {
65
+ enableOverride = false,
66
+ overrideStorageKey = "company-subdomain",
67
+ reservedSubdomains = [],
68
+ } = opts
40
69
 
41
70
  const [subdomain] = useState<string | undefined>(() => {
42
71
  if (enableOverride) {
@@ -44,7 +73,7 @@ export function useCompanySubdomain(
44
73
  if (override) return override
45
74
  }
46
75
  if (typeof window === "undefined") return undefined
47
- return getSubdomain(window.location.hostname)
76
+ return getSubdomain(window.location.hostname, reservedSubdomains)
48
77
  })
49
78
 
50
79
  return { subdomain }