@lessly/ui 2.3.0 → 3.0.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.
package/dist/index.d.ts CHANGED
@@ -3146,10 +3146,10 @@ interface BeneficialOwnerPayload {
3146
3146
  /** The submit payload — snake_case, exactly as the organization-creation endpoint takes it. */
3147
3147
  interface OrganizationOnboardingPayload {
3148
3148
  name: string;
3149
- legal_name?: string;
3150
- owner_name?: string;
3151
- country_of_incorporation?: string;
3152
- residency_country?: string;
3149
+ legal_name: string;
3150
+ owner_name: string;
3151
+ country_of_incorporation: string;
3152
+ residency_country: string;
3153
3153
  beneficial_owners: BeneficialOwnerPayload[];
3154
3154
  /** Only present when no listed owner holds a controlling share. */
3155
3155
  ownership_confirmed?: boolean;
@@ -3163,10 +3163,6 @@ interface OrganizationOnboardingDefaults {
3163
3163
  beneficial_owners?: BeneficialOwnerPayload[];
3164
3164
  }
3165
3165
  interface OrganizationOnboardingFormProps {
3166
- /** Makes the country of incorporation mandatory. Mirrors the server-side requirement the
3167
- * consumer is configured for. The ownership confirmation is required whenever it is shown,
3168
- * independently of this flag. */
3169
- requireSanctionsFields: boolean;
3170
3166
  onSubmit: (payload: OrganizationOnboardingPayload) => void;
3171
3167
  defaultValues?: OrganizationOnboardingDefaults;
3172
3168
  /** Disables the submit button and swaps its label while the caller's request is in flight. */
@@ -3186,7 +3182,7 @@ interface OrganizationOnboardingFormProps {
3186
3182
  * new organization. Presentational and self-contained — it never calls an API and never
3187
3183
  * navigates; the caller wraps it in its own dialog and handles the outcome of `onSubmit`.
3188
3184
  */
3189
- declare function OrganizationOnboardingForm({ requireSanctionsFields, onSubmit, defaultValues, submitting, serverError, violations, countries, submitLabel, onCancel, className, }: OrganizationOnboardingFormProps): React$1.JSX.Element;
3185
+ declare function OrganizationOnboardingForm({ onSubmit, defaultValues, submitting, serverError, violations, countries, submitLabel, onCancel, className, }: OrganizationOnboardingFormProps): React$1.JSX.Element;
3190
3186
 
3191
3187
  /**
3192
3188
  * The width steps a trailing cell may take, as literal classes. A width is picked from this map and
package/dist/index.js CHANGED
@@ -6781,10 +6781,20 @@ var AUTH_BUTTON_SHADOW = "var(--auth-btn-shadow)";
6781
6781
  import { jsx as jsx98, jsxs as jsxs65 } from "react/jsx-runtime";
6782
6782
  var CONTROLLER_SHARE_PCT = 50;
6783
6783
  var MAX_BENEFICIAL_OWNERS = 50;
6784
+ var REQUIRED_FIELD_LABELS = {
6785
+ name: "Organization name",
6786
+ legalName: "Legal name",
6787
+ ownerName: "Owner name",
6788
+ countryOfIncorporation: "Country of incorporation",
6789
+ residencyCountry: "Country of residency"
6790
+ };
6784
6791
  var OWNERSHIP_CONFIRMATION_MESSAGE = "Please confirm the ownership details by ticking the box";
6785
6792
  function isOwnershipViolation(violation) {
6786
6793
  return /ownership[_\s-]?confirmed/i.test(violation);
6787
6794
  }
6795
+ function RequiredMark() {
6796
+ return /* @__PURE__ */ jsx98("span", { className: "text-text-danger", children: " *" });
6797
+ }
6788
6798
  function parseShare(raw) {
6789
6799
  if (!/^\d{1,3}$/.test(raw.trim())) return null;
6790
6800
  const n = Number(raw);
@@ -6802,7 +6812,6 @@ function initialRows(owners) {
6802
6812
  }));
6803
6813
  }
6804
6814
  function OrganizationOnboardingForm({
6805
- requireSanctionsFields,
6806
6815
  onSubmit,
6807
6816
  defaultValues,
6808
6817
  submitting,
@@ -6827,6 +6836,7 @@ function OrganizationOnboardingForm({
6827
6836
  );
6828
6837
  const [ownershipConfirmed, setOwnershipConfirmed] = React83.useState(false);
6829
6838
  const [confirmationAttempted, setConfirmationAttempted] = React83.useState(false);
6839
+ const [requiredAttempted, setRequiredAttempted] = React83.useState(false);
6830
6840
  const nextKeyRef = React83.useRef(owners.length);
6831
6841
  const submittingRef = React83.useRef(false);
6832
6842
  const trimmed = name.trim();
@@ -6840,9 +6850,16 @@ function OrganizationOnboardingForm({
6840
6850
  (share) => share !== null && share >= CONTROLLER_SHARE_PCT
6841
6851
  );
6842
6852
  const needsOwnershipConfirmation = !hasController;
6843
- const missingCountry = requireSanctionsFields && countryOfIncorporation === "";
6853
+ const missingRequired = [
6854
+ [trimmed, REQUIRED_FIELD_LABELS.name],
6855
+ [legalName.trim(), REQUIRED_FIELD_LABELS.legalName],
6856
+ [ownerName.trim(), REQUIRED_FIELD_LABELS.ownerName],
6857
+ [countryOfIncorporation, REQUIRED_FIELD_LABELS.countryOfIncorporation],
6858
+ [residencyCountry, REQUIRED_FIELD_LABELS.residencyCountry]
6859
+ ].filter(([value]) => value === "").map(([, label]) => label);
6844
6860
  const missingConfirmation = needsOwnershipConfirmation && !ownershipConfirmed;
6845
- const canSubmit = trimmed !== "" && ownersValid && !missingCountry && !submitting;
6861
+ const canSubmit = ownersValid && !submitting;
6862
+ const showRequiredError = requiredAttempted && missingRequired.length > 0;
6846
6863
  const ownershipViolations = needsOwnershipConfirmation ? (violations ?? []).filter(isOwnershipViolation) : [];
6847
6864
  const otherViolations = (violations ?? []).filter(
6848
6865
  (violation) => !ownershipViolations.includes(violation)
@@ -6861,7 +6878,8 @@ function OrganizationOnboardingForm({
6861
6878
  const handleSubmit = (event) => {
6862
6879
  event.preventDefault();
6863
6880
  if (!canSubmit || submittingRef.current) return;
6864
- if (missingConfirmation) {
6881
+ if (missingRequired.length > 0 || missingConfirmation) {
6882
+ setRequiredAttempted(true);
6865
6883
  setConfirmationAttempted(true);
6866
6884
  return;
6867
6885
  }
@@ -6873,10 +6891,10 @@ function OrganizationOnboardingForm({
6873
6891
  }));
6874
6892
  onSubmit({
6875
6893
  name: trimmed,
6876
- ...legalName.trim() !== "" ? { legal_name: legalName.trim() } : {},
6877
- ...ownerName.trim() !== "" ? { owner_name: ownerName.trim() } : {},
6878
- ...countryOfIncorporation !== "" ? { country_of_incorporation: countryOfIncorporation } : {},
6879
- ...residencyCountry !== "" ? { residency_country: residencyCountry } : {},
6894
+ legal_name: legalName.trim(),
6895
+ owner_name: ownerName.trim(),
6896
+ country_of_incorporation: countryOfIncorporation,
6897
+ residency_country: residencyCountry,
6880
6898
  beneficial_owners: beneficialOwners,
6881
6899
  // Only meaningful — and only collected — when the list shows no controlling owner.
6882
6900
  ...needsOwnershipConfirmation ? { ownership_confirmed: ownershipConfirmed } : {}
@@ -6898,7 +6916,7 @@ function OrganizationOnboardingForm({
6898
6916
  const countryField = (params) => /* @__PURE__ */ jsxs65("div", { className: "space-y-1.5", children: [
6899
6917
  /* @__PURE__ */ jsxs65(Label2, { htmlFor: params.id, children: [
6900
6918
  params.label,
6901
- params.required && /* @__PURE__ */ jsx98("span", { className: "text-text-danger", children: " *" })
6919
+ /* @__PURE__ */ jsx98(RequiredMark, {})
6902
6920
  ] }),
6903
6921
  /* @__PURE__ */ jsx98(
6904
6922
  Select,
@@ -6915,7 +6933,10 @@ function OrganizationOnboardingForm({
6915
6933
  ] });
6916
6934
  return /* @__PURE__ */ jsxs65("form", { onSubmit: handleSubmit, className: cn("space-y-4", className), children: [
6917
6935
  /* @__PURE__ */ jsxs65("div", { className: "space-y-1.5", children: [
6918
- /* @__PURE__ */ jsx98(Label2, { htmlFor: "create-org-name", children: "Organization name" }),
6936
+ /* @__PURE__ */ jsxs65(Label2, { htmlFor: "create-org-name", children: [
6937
+ REQUIRED_FIELD_LABELS.name,
6938
+ /* @__PURE__ */ jsx98(RequiredMark, {})
6939
+ ] }),
6919
6940
  /* @__PURE__ */ jsx98(
6920
6941
  Input,
6921
6942
  {
@@ -6928,7 +6949,10 @@ function OrganizationOnboardingForm({
6928
6949
  )
6929
6950
  ] }),
6930
6951
  /* @__PURE__ */ jsxs65("div", { className: "space-y-1.5", children: [
6931
- /* @__PURE__ */ jsx98(Label2, { htmlFor: "create-org-legal-name", children: "Legal name" }),
6952
+ /* @__PURE__ */ jsxs65(Label2, { htmlFor: "create-org-legal-name", children: [
6953
+ REQUIRED_FIELD_LABELS.legalName,
6954
+ /* @__PURE__ */ jsx98(RequiredMark, {})
6955
+ ] }),
6932
6956
  /* @__PURE__ */ jsx98(
6933
6957
  Input,
6934
6958
  {
@@ -6941,7 +6965,10 @@ function OrganizationOnboardingForm({
6941
6965
  )
6942
6966
  ] }),
6943
6967
  /* @__PURE__ */ jsxs65("div", { className: "space-y-1.5", children: [
6944
- /* @__PURE__ */ jsx98(Label2, { htmlFor: "create-org-owner-name", children: "Owner name" }),
6968
+ /* @__PURE__ */ jsxs65(Label2, { htmlFor: "create-org-owner-name", children: [
6969
+ REQUIRED_FIELD_LABELS.ownerName,
6970
+ /* @__PURE__ */ jsx98(RequiredMark, {})
6971
+ ] }),
6945
6972
  /* @__PURE__ */ jsx98(
6946
6973
  Input,
6947
6974
  {
@@ -6955,17 +6982,15 @@ function OrganizationOnboardingForm({
6955
6982
  ] }),
6956
6983
  countryField({
6957
6984
  id: "create-org-country",
6958
- label: "Country of incorporation",
6985
+ label: REQUIRED_FIELD_LABELS.countryOfIncorporation,
6959
6986
  value: countryOfIncorporation,
6960
- onChange: setCountryOfIncorporation,
6961
- required: requireSanctionsFields
6987
+ onChange: setCountryOfIncorporation
6962
6988
  }),
6963
6989
  countryField({
6964
6990
  id: "create-org-residency",
6965
- label: "Country of residency",
6991
+ label: REQUIRED_FIELD_LABELS.residencyCountry,
6966
6992
  value: residencyCountry,
6967
- onChange: setResidencyCountry,
6968
- required: false
6993
+ onChange: setResidencyCountry
6969
6994
  }),
6970
6995
  /* @__PURE__ */ jsxs65("div", { className: "space-y-2", children: [
6971
6996
  /* @__PURE__ */ jsxs65("div", { className: "flex items-center justify-between", children: [
@@ -7071,7 +7096,7 @@ function OrganizationOnboardingForm({
7071
7096
  className: "text-xs font-regular leading-snug",
7072
7097
  children: [
7073
7098
  "I confirm the ownership structure above is complete and correct",
7074
- /* @__PURE__ */ jsx98("span", { className: "text-text-danger", children: " *" })
7099
+ /* @__PURE__ */ jsx98(RequiredMark, {})
7075
7100
  ]
7076
7101
  }
7077
7102
  )
@@ -7086,7 +7111,8 @@ function OrganizationOnboardingForm({
7086
7111
  }
7087
7112
  )
7088
7113
  ] }),
7089
- (serverError || otherViolations.length > 0) && /* @__PURE__ */ jsxs65(InlineError, { children: [
7114
+ showRequiredError && /* @__PURE__ */ jsx98(InlineError, { "data-testid": "create-org-required-error", children: missingRequired.length === 1 ? `${missingRequired[0]} is required` : `These fields are required: ${missingRequired.join(", ")}` }),
7115
+ (serverError || otherViolations.length > 0) && /* @__PURE__ */ jsxs65(InlineError, { "data-testid": "create-org-server-error", children: [
7090
7116
  serverError,
7091
7117
  otherViolations.length > 0 && /* @__PURE__ */ jsx98("ul", { "data-testid": "create-org-violations", className: "mt-1 list-disc pl-4", children: otherViolations.map((violation) => /* @__PURE__ */ jsx98("li", { children: violation }, violation)) })
7092
7118
  ] }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lessly/ui",
3
- "version": "2.3.0",
3
+ "version": "3.0.0",
4
4
  "description": "Lessly design system — shared UI primitives, tokens, and theme",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.30.3",
@@ -50,7 +50,8 @@
50
50
  "build-site": "pnpm build && vite build --config site/vite.config.ts",
51
51
  "test-site": "node --test site/*.test.mjs",
52
52
  "test-site-app": "vitest run --config site/vitest.config.ts",
53
- "gen-changelog": "node site/scripts/gen-changelog.mjs"
53
+ "gen-changelog": "node site/scripts/gen-changelog.mjs",
54
+ "build:email-logo": "tsx scripts/build-email-logo.mts"
54
55
  },
55
56
  "publishConfig": {
56
57
  "registry": "https://registry.npmjs.org/",
@@ -111,6 +112,9 @@
111
112
  "devDependencies": {
112
113
  "@changesets/cli": "^2.31.0",
113
114
  "@eslint/js": "^9.39.5",
115
+ "@react-email/components": "^0.5.6",
116
+ "@react-email/render": "^1.3.2",
117
+ "@resvg/resvg-js": "^2.6.2",
114
118
  "@storybook/addon-essentials": "^8.6.14",
115
119
  "@storybook/blocks": "8.6.18",
116
120
  "@storybook/react": "^8.6.18",