@marianmeres/stuic 3.160.0 → 3.161.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.
@@ -40,36 +40,36 @@ interface RegisterFieldConfig {
40
40
 
41
41
  ## RegisterForm — Props
42
42
 
43
- | Prop | Type | Default | Description |
44
- | --------------------------- | --------------------------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
45
- | `formData` | `RegisterFormData` | empty | Bindable form data. |
46
- | `onSubmit` | `(data: RegisterFormData) => void` | required | Called after client-side validation passes. |
47
- | `isSubmitting` | `boolean` | `false` | Disables the CTA during submission. |
48
- | `submitDisabled` | `boolean` | `false` | Consumer-owned submit block. Disables the CTA **and** blocks `onSubmit`. |
49
- | `errors` | `RegisterFormValidationError[]` | `[]` | Field-specific server errors (merged with internal validation). See [Server errors](#server-supplied-errors). |
50
- | `error` | `string` | - | General error rendered as a `DismissibleMessage` above the form. |
51
- | `showEmail` | `boolean` | `true` | Render the email field. `false` **unmounts** it and skips its validation. |
52
- | `showPassword` | `boolean` | `true` | Render the password field (and, transitively, the confirm field). |
53
- | `showPasswordConfirm` | `boolean` | `true` | Render the password-confirm field. Subordinate to `showPassword`. |
54
- | `passwordMinLength` | `number` | `8` | Minimum password length (fed into both the FieldInput attribute and the validator). |
55
- | `credentialsSlot` | `Snippet<[{ formData, fieldError }]>` | - | Rendered at the credentials position (after the core fields, before bottom extra fields). |
56
- | `emailFieldProps` | `Partial<FieldInputProps>` | - | Passthrough props for the built-in email field. |
57
- | `passwordFieldProps` | `Partial<FieldInputProps>` | - | Passthrough props for the built-in password field. |
58
- | `passwordConfirmFieldProps` | `Partial<FieldInputProps>` | - | Passthrough props for the built-in confirm field. |
59
- | `extraFields` | `RegisterFieldConfig[]` | `[]` | Declarative extra fields. Rendered as `FieldInput`s positioned top or bottom. |
60
- | `extraFieldsSlot` | `Snippet<[{ formData, fieldError }]>` | - | Escape hatch for non-FieldInput extras. Rendered after declarative bottom fields. |
61
- | `topFieldsSeparator` | `boolean` | auto | Section rule below the top-position extra fields. Auto-on when they are followed by the top social block or by a `credentialsSlot` that has replaced the credentials. |
62
- | `submitLabel` | `string` | i18n | Override the CTA label. |
63
- | `submittingLabel` | `string` | i18n | Override the CTA label while submitting. |
64
- | `submitButton` | `Snippet<[{ isSubmitting, disabled }]>` | - | Override the entire CTA section. `disabled` is `isSubmitting \|\| submitDisabled`. |
65
- | `socialLogins` | `Snippet` | - | Social/OAuth buttons. A divider is shown when set. |
66
- | `socialPosition` | `"top" \| "bottom"` | `"bottom"` | `"top"` renders the block above the credentials, with the divider **below** the buttons. |
67
- | `socialDividerLabel` | `string \| false` | i18n | Override (or hide with `false`) the divider. Defaults to `social_divider` ("or continue with") at the bottom, `social_divider_alt` ("or") at the top. |
68
- | `footer` | `Snippet` | - | Content below the form (e.g., "Already have an account? Log in"). |
69
- | `notifications` | `NotificationsStack` | - | When set, general errors are also pushed via `notifications.error()`. |
70
- | `t` | `TranslateFn` | English | i18n function. |
71
- | `unstyled` / `class` | - | - | Standard styling escape hatches. |
72
- | `el` | `HTMLFormElement` | - | Bindable form element. |
43
+ | Prop | Type | Default | Description |
44
+ | --------------------------- | --------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
45
+ | `formData` | `RegisterFormData` | empty | Bindable form data. |
46
+ | `onSubmit` | `(data: RegisterFormData) => void` | required | Called after client-side validation passes. |
47
+ | `isSubmitting` | `boolean` | `false` | Disables the CTA during submission. |
48
+ | `submitDisabled` | `boolean` | `false` | Consumer-owned submit block. Disables the CTA **and** blocks `onSubmit`. |
49
+ | `errors` | `RegisterFormValidationError[]` | `[]` | Field-specific server errors (merged with internal validation). See [Server errors](#server-supplied-errors). |
50
+ | `error` | `string` | - | General error rendered as a `DismissibleMessage` above the form. |
51
+ | `showEmail` | `boolean` | `true` | Render the email field. `false` **unmounts** it and skips its validation. |
52
+ | `showPassword` | `boolean` | `true` | Render the password field (and, transitively, the confirm field). |
53
+ | `showPasswordConfirm` | `boolean` | `true` | Render the password-confirm field. Subordinate to `showPassword`. |
54
+ | `passwordMinLength` | `number` | `8` | Minimum password length (fed into both the FieldInput attribute and the validator). |
55
+ | `credentialsSlot` | `Snippet<[{ formData, fieldError }]>` | - | Rendered at the credentials position (after the core fields, before bottom extra fields). |
56
+ | `emailFieldProps` | `Partial<FieldInputProps>` | - | Passthrough props for the built-in email field. |
57
+ | `passwordFieldProps` | `Partial<FieldInputProps>` | - | Passthrough props for the built-in password field. |
58
+ | `passwordConfirmFieldProps` | `Partial<FieldInputProps>` | - | Passthrough props for the built-in confirm field. |
59
+ | `extraFields` | `RegisterFieldConfig[]` | `[]` | Declarative extra fields. Rendered as `FieldInput`s positioned top or bottom. |
60
+ | `extraFieldsSlot` | `Snippet<[{ formData, fieldError }]>` | - | Escape hatch for non-FieldInput extras. Rendered after declarative bottom fields. |
61
+ | `topFieldsSeparator` | `boolean` | `true` | Section rule closing the top-position extra-field group. Drawn whenever at least one such field exists, whatever follows it. `false` opts out. |
62
+ | `submitLabel` | `string` | i18n | Override the CTA label. |
63
+ | `submittingLabel` | `string` | i18n | Override the CTA label while submitting. |
64
+ | `submitButton` | `Snippet<[{ isSubmitting, disabled }]>` | - | Override the entire CTA section. `disabled` is `isSubmitting \|\| submitDisabled`. |
65
+ | `socialLogins` | `Snippet` | - | Social/OAuth buttons. A divider is shown when set. |
66
+ | `socialPosition` | `"top" \| "bottom"` | `"bottom"` | `"top"` renders the block above the credentials, with the divider **below** the buttons. |
67
+ | `socialDividerLabel` | `string \| false` | i18n | Override (or hide with `false`) the divider. Defaults to `social_divider` ("or continue with") at the bottom, `social_divider_alt` ("or") at the top. |
68
+ | `footer` | `Snippet` | - | Content below the form (e.g., "Already have an account? Log in"). |
69
+ | `notifications` | `NotificationsStack` | - | When set, general errors are also pushed via `notifications.error()`. |
70
+ | `t` | `TranslateFn` | English | i18n function. |
71
+ | `unstyled` / `class` | - | - | Standard styling escape hatches. |
72
+ | `el` | `HTMLFormElement` | - | Bindable form element. |
73
73
 
74
74
  ### Imperative methods (via `bind:this`)
75
75
 
@@ -215,7 +215,7 @@ Once an external party has confirmed who the user is, the credential fields are
215
215
 
216
216
  Call `form.focusField("tenant_id")` right after the provider confirms: the button the user clicked is about to unmount, and without an explicit move focus falls to `<body>` — a keyboard user's next Tab restarts at the top of the document.
217
217
 
218
- Those top-position fields are closed off with a section rule here, automatically. At the form's ordinary field rhythm the last of them sits one field-gap above the first provider button and reads as a caption for it; the break says instead that the fields are settled and what follows is a choice. It turns itself on exactly when the fields are followed by something that is not another input — the top social block, or a `credentialsSlot` standing in for the whole credential block so it survives the switch from "pick a provider" to "signing up as jane@…" without the layout moving. `topFieldsSeparator={true | false}` overrides the decision in either direction.
218
+ Those top-position fields are closed off with a section rule. At the form's ordinary field rhythm the last of them sits one field-gap above the first provider button and reads as a caption for it; the break says instead that the workspace id is settled and what follows is the account. The rule is not conditioned on what comes next provider buttons, a `credentialsSlot`, or the plain credentials all get it so it does not blink in and out as this flow moves from "pick a provider" to "signing up as jane@…", and a reader of the call site does not have to work out which combination of other props switched it on. `topFieldsSeparator={false}` opts out.
219
219
 
220
220
  Other shapes the same three props cover:
221
221
 
@@ -310,7 +310,7 @@ The social block carries `data-position="top" \| "bottom"` (suppressed under `un
310
310
 
311
311
  `credentialsSlot` content is wrapped in `.stuic-register-form-credentials` (suppressed under `unstyled`) so it inherits the same bottom rhythm the fields have — the form itself is a zero-gap flex column.
312
312
 
313
- Top-position extra fields are wrapped in `.stuic-register-form-fields-top` (suppressed under `unstyled`), which carries `data-separator` when the rule is on. The wrapper is otherwise inert — the fields keep their own margins — so targeting `[data-separator]` is the way to restyle the break without touching the ungrouped case. The default padding stacks on top of the last field's own `margin-bottom`, which is why the two spacing tokens are not equal.
313
+ Top-position extra fields are wrapped in `.stuic-register-form-fields-top` (suppressed under `unstyled`), which carries `data-separator` unless `topFieldsSeparator={false}`. The wrapper is otherwise inert — the fields keep their own margins — so targeting `[data-separator]` is the way to restyle the break without touching the ungrouped case. The default padding stacks on top of the last field's own `margin-bottom`, which is why the two spacing tokens are not equal.
314
314
 
315
315
  ## Gotchas
316
316
 
@@ -128,17 +128,16 @@
128
128
  * Close the top-position extra fields with a section break — a hairline
129
129
  * rule plus extra space below the group.
130
130
  *
131
- * Those fields are the ones required whichever way the user signs up (a
132
- * workspace id, an invite code), so what follows them in an identity-first
133
- * layout is a *choice*: provider buttons, or a block standing in for the
134
- * credentials. At the form's ordinary field rhythm the last of them reads
135
- * as a caption for the first button below it the break makes the group a
136
- * section of its own instead.
131
+ * A field is at the top position because it is about something other than
132
+ * the credentials (a workspace id, an invite code, an org name), so the
133
+ * group is drawn as its own section. Without the break the last of them
134
+ * sits at the ordinary field gap above whatever comes next and reads as a
135
+ * caption for it a label over the first provider button, or just another
136
+ * row of the credential column.
137
137
  *
138
- * Default: auto on when the top fields are followed by the top-position
139
- * social block or by a `credentialsSlot` that has replaced the credentials
140
- * entirely; off otherwise, since a plain column of inputs does not want a
141
- * rule drawn through the middle of it.
138
+ * Default: true whenever there is at least one top-position field,
139
+ * regardless of what follows. Set `false` for a form whose top fields
140
+ * really do belong to the same column as the credentials.
142
141
  */
143
142
  topFieldsSeparator?: boolean;
144
143
 
@@ -268,15 +267,15 @@
268
267
  // validated against it).
269
268
  let renderPasswordConfirm = $derived(showPassword && showPasswordConfirm);
270
269
 
271
- // The section break below the top fields earns its place only when the next
272
- // thing down is NOT another plain input: the top social block, or a slot that
273
- // has taken the credentials' place. Anywhere else the form is a single column
274
- // of fields and a rule through the middle of it is noise.
275
- let renderTopFieldsSeparator = $derived(
276
- topFieldsSeparator ??
277
- ((socialPosition === "top" && !!socialLogins) ||
278
- (!!credentialsSlot && !showEmail && !showPassword))
279
- );
270
+ // A field at the top position is there because it is about something other
271
+ // than the credentials the workspace, the invite, the org so it is closed
272
+ // off as its own section whichever way the sign-up continues below it.
273
+ // Deliberately NOT conditioned on what follows (provider buttons, a
274
+ // credentialsSlot, plain inputs): the last top field otherwise sits one field
275
+ // gap above the next thing and reads as a caption for it either way, and a
276
+ // rule that comes and goes with an unrelated prop is not explicable from the
277
+ // call site. `topFieldsSeparator={false}` opts out.
278
+ let renderTopFieldsSeparator = $derived(topFieldsSeparator ?? true);
280
279
 
281
280
  // Internal validation errors (set on submit)
282
281
  let internalErrors = $state<RegisterFormValidationError[]>([]);
@@ -101,17 +101,16 @@ export interface Props extends Omit<HTMLAttributes<HTMLFormElement>, "children">
101
101
  * Close the top-position extra fields with a section break — a hairline
102
102
  * rule plus extra space below the group.
103
103
  *
104
- * Those fields are the ones required whichever way the user signs up (a
105
- * workspace id, an invite code), so what follows them in an identity-first
106
- * layout is a *choice*: provider buttons, or a block standing in for the
107
- * credentials. At the form's ordinary field rhythm the last of them reads
108
- * as a caption for the first button below it the break makes the group a
109
- * section of its own instead.
104
+ * A field is at the top position because it is about something other than
105
+ * the credentials (a workspace id, an invite code, an org name), so the
106
+ * group is drawn as its own section. Without the break the last of them
107
+ * sits at the ordinary field gap above whatever comes next and reads as a
108
+ * caption for it a label over the first provider button, or just another
109
+ * row of the credential column.
110
110
  *
111
- * Default: auto on when the top fields are followed by the top-position
112
- * social block or by a `credentialsSlot` that has replaced the credentials
113
- * entirely; off otherwise, since a plain column of inputs does not want a
114
- * rule drawn through the middle of it.
111
+ * Default: true whenever there is at least one top-position field,
112
+ * regardless of what follows. Set `false` for a form whose top fields
113
+ * really do belong to the same column as the credentials.
115
114
  */
116
115
  topFieldsSeparator?: boolean;
117
116
  /** Override CTA label */
@@ -75,7 +75,7 @@
75
75
  ]
76
76
  >;
77
77
 
78
- /** Section break below the top-position extra fields. Default: auto. */
78
+ /** Section break below the top-position extra fields. Default: true. */
79
79
  topFieldsSeparator?: InnerProps["topFieldsSeparator"];
80
80
 
81
81
  /** Override CTA label */
@@ -51,7 +51,7 @@ export interface Props {
51
51
  fieldError: (name: string) => string | undefined;
52
52
  }
53
53
  ]>;
54
- /** Section break below the top-position extra fields. Default: auto. */
54
+ /** Section break below the top-position extra fields. Default: true. */
55
55
  topFieldsSeparator?: InnerProps["topFieldsSeparator"];
56
56
  /** Override CTA label */
57
57
  submitLabel?: string;
@@ -46,11 +46,10 @@
46
46
  margin-bottom: var(--stuic-register-form-credentials-margin-bottom);
47
47
  }
48
48
 
49
- /* Top-position extra fields. The group wrapper is deliberately inert until
50
- `data-separator` is set those fields are otherwise just the first rows of
51
- the same single column, and a rule through the middle of a column of inputs
52
- is noise. With it, the group becomes its own section: what follows is a
53
- choice of sign-up path, not another field. */
49
+ /* Top-position extra fields. `data-separator` is on unless the consumer opts
50
+ out, so the group reads as its own section rather than as the first rows of
51
+ the credential column; the wrapper is inert without it, leaving the fields
52
+ their own margins. */
54
53
  .stuic-register-form-fields-top[data-separator] {
55
54
  padding-bottom: var(--stuic-register-form-fields-top-padding-bottom);
56
55
  margin-bottom: var(--stuic-register-form-fields-top-margin-bottom);
@@ -300,7 +300,7 @@ Prefix: `--stuic-login-form-*`
300
300
 
301
301
  Standalone registration form. Mirrors `LoginForm` conventions: `formData`, `onSubmit`, validation, errors, i18n, notifications, social-logins. Adds declarative `extraFields` (top/bottom positioning, custom validators) and an `extraFieldsSlot` escape hatch (e.g., terms checkbox).
302
302
 
303
- Also covers **identity-first signup** (identity established by an OAuth provider / invite / magic link before the account exists): `showEmail` / `showPassword` unmount the credential fields, `credentialsSlot` replaces them, `socialPosition="top"` moves the provider buttons above the credentials, and the top-position extra fields (workspace id, invite code — required on every path) are closed off with a section rule so they don't read as a caption for the first provider button (`topFieldsSeparator`, auto).
303
+ Also covers **identity-first signup** (identity established by an OAuth provider / invite / magic link before the account exists): `showEmail` / `showPassword` unmount the credential fields, `credentialsSlot` replaces them, `socialPosition="top"` moves the provider buttons above the credentials, and the top-position extra fields (workspace id, invite code — required on every path) are closed off with a section rule so they don't read as a caption for the first provider button (`topFieldsSeparator`, on by default whenever such a field exists).
304
304
 
305
305
  ### Exports
306
306
 
@@ -317,29 +317,29 @@ Also covers **identity-first signup** (identity established by an OAuth provider
317
317
 
318
318
  ### Key Props
319
319
 
320
- | Prop | Type | Default | Description |
321
- | ---------------------------------------------------------------------- | ------------------------------- | ---------- | -------------------------------------------------------------------------------- |
322
- | `formData` | `RegisterFormData` | empty | Bindable form data |
323
- | `onSubmit` | `(data) => void` | required | Submit callback |
324
- | `isSubmitting` | `boolean` | `false` | Disables CTA |
325
- | `submitDisabled` | `boolean` | `false` | Consumer-owned block: disables CTA + blocks submit |
326
- | `errors` | `RegisterFormValidationError[]` | `[]` | Server field errors — self-clearing (see below) |
327
- | `error` | `string` | — | General error (alert above form) |
328
- | `showEmail` | `boolean` | `true` | Render (mount) the email field |
329
- | `showPassword` | `boolean` | `true` | Render (mount) the password + confirm fields |
330
- | `showPasswordConfirm` | `boolean` | `true` | Render password-confirm field |
331
- | `passwordMinLength` | `number` | `8` | Min password length (input + validator) |
332
- | `credentialsSlot` | `Snippet` | — | Content at the credentials position |
333
- | `emailFieldProps` / `passwordFieldProps` / `passwordConfirmFieldProps` | `Partial<FieldInputProps>` | — | Passthrough props per core field (`validate` composed, `value` ignored) |
334
- | `extraFields` | `RegisterFieldConfig[]` | `[]` | Declarative extra fields (top/bottom) |
335
- | `extraFieldsSlot` | `Snippet` | — | Escape-hatch for non-FieldInput extras |
336
- | `topFieldsSeparator` | `boolean` | auto | Section rule below the top-position extra fields (auto-on when a choice follows) |
337
- | `submitButton` | `Snippet` | — | Custom CTA section |
338
- | `socialLogins` | `Snippet` | — | OAuth buttons |
339
- | `socialPosition` | `"top" \| "bottom"` | `"bottom"` | Social block above the credentials or after the CTA |
340
- | `footer` | `Snippet` | — | Content below form |
341
- | `notifications` | `NotificationsStack` | — | Route errors to notifications |
342
- | `t` | `TranslateFn` | built-in | Translation function |
320
+ | Prop | Type | Default | Description |
321
+ | ---------------------------------------------------------------------- | ------------------------------- | ---------- | ------------------------------------------------------------------------- |
322
+ | `formData` | `RegisterFormData` | empty | Bindable form data |
323
+ | `onSubmit` | `(data) => void` | required | Submit callback |
324
+ | `isSubmitting` | `boolean` | `false` | Disables CTA |
325
+ | `submitDisabled` | `boolean` | `false` | Consumer-owned block: disables CTA + blocks submit |
326
+ | `errors` | `RegisterFormValidationError[]` | `[]` | Server field errors — self-clearing (see below) |
327
+ | `error` | `string` | — | General error (alert above form) |
328
+ | `showEmail` | `boolean` | `true` | Render (mount) the email field |
329
+ | `showPassword` | `boolean` | `true` | Render (mount) the password + confirm fields |
330
+ | `showPasswordConfirm` | `boolean` | `true` | Render password-confirm field |
331
+ | `passwordMinLength` | `number` | `8` | Min password length (input + validator) |
332
+ | `credentialsSlot` | `Snippet` | — | Content at the credentials position |
333
+ | `emailFieldProps` / `passwordFieldProps` / `passwordConfirmFieldProps` | `Partial<FieldInputProps>` | — | Passthrough props per core field (`validate` composed, `value` ignored) |
334
+ | `extraFields` | `RegisterFieldConfig[]` | `[]` | Declarative extra fields (top/bottom) |
335
+ | `extraFieldsSlot` | `Snippet` | — | Escape-hatch for non-FieldInput extras |
336
+ | `topFieldsSeparator` | `boolean` | `true` | Section rule closing the top-position extra-field group; `false` opts out |
337
+ | `submitButton` | `Snippet` | — | Custom CTA section |
338
+ | `socialLogins` | `Snippet` | — | OAuth buttons |
339
+ | `socialPosition` | `"top" \| "bottom"` | `"bottom"` | Social block above the credentials or after the CTA |
340
+ | `footer` | `Snippet` | — | Content below form |
341
+ | `notifications` | `NotificationsStack` | — | Route errors to notifications |
342
+ | `t` | `TranslateFn` | built-in | Translation function |
343
343
 
344
344
  **Imperative** (`bind:this`): `validate()`, `scrollToFirstError(opts?)`, `focusField(name)` — also forwarded by `RegisterFormModal`.
345
345
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "3.160.0",
3
+ "version": "3.161.0",
4
4
  "packageManager": "pnpm@11.5.0",
5
5
  "scripts": {
6
6
  "dev": "vite dev",