@samuel-charpentier/sform 0.0.2 → 0.0.4
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 +281 -76
- package/dist/Sform/SIssues.svelte +49 -0
- package/dist/Sform/SIssues.svelte.d.ts +14 -0
- package/dist/Sform/SResult.svelte +36 -0
- package/dist/Sform/SResult.svelte.d.ts +39 -0
- package/dist/Sform/Sfield.svelte +7 -1
- package/dist/Sform/Sform.svelte +2 -1
- package/dist/Sform/context.svelte.d.ts +11 -2
- package/dist/Sform/context.svelte.js +62 -2
- package/dist/Sform/index.d.ts +3 -1
- package/dist/Sform/index.js +2 -0
- package/dist/Sform/inputs/ButtonInput.svelte +26 -45
- package/dist/Sform/inputs/ButtonInput.svelte.d.ts +43 -29
- package/dist/Sform/inputs/CheckboxGroupInput.svelte +3 -16
- package/dist/Sform/inputs/HiddenInput.svelte +10 -0
- package/dist/Sform/inputs/HiddenInput.svelte.d.ts +4 -0
- package/dist/Sform/inputs/RadioInput.svelte +3 -5
- package/dist/Sform/inputs/TextInput.svelte +26 -30
- package/dist/Sform/sform.css +14 -0
- package/dist/Sform/types.d.ts +95 -15
- package/dist/Sform/utils/Fieldset.svelte +24 -0
- package/dist/Sform/utils/Fieldset.svelte.d.ts +4 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/Sform/types.d.ts
CHANGED
|
@@ -82,7 +82,7 @@ export type AllowedSfieldType<T> = {
|
|
|
82
82
|
*/
|
|
83
83
|
export type InputType = 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search' | 'date' | 'datetime-local' | 'time' | 'month' | 'week' | 'color' | 'textarea' | 'select' | 'checkbox' | 'checkbox-group' | 'radio' | 'file' | 'hidden' | 'range' | 'toggle' | 'toggle-options' | 'masked';
|
|
84
84
|
/** Text-like input types */
|
|
85
|
-
export type TextInputType = 'text' | 'email' | 'tel' | 'url' | 'search' | 'date' | 'datetime-local' | 'time' | 'month' | 'week' | 'color' | 'file'
|
|
85
|
+
export type TextInputType = 'text' | 'email' | 'tel' | 'url' | 'search' | 'date' | 'datetime-local' | 'time' | 'month' | 'week' | 'color' | 'file';
|
|
86
86
|
/** Numeric input types */
|
|
87
87
|
export type NumericInputType = 'number';
|
|
88
88
|
/**
|
|
@@ -105,6 +105,37 @@ export type RemoteForm<Input extends RemoteFormInput | void = RemoteFormInput, O
|
|
|
105
105
|
* The .for(id) method returns Omit<RemoteForm, 'for'>, so this type accepts both.
|
|
106
106
|
*/
|
|
107
107
|
export type RemoteFormInstance<Input extends RemoteFormInput | void = RemoteFormInput, Output = unknown> = SvelteKitRemoteForm<Input, Output> | Omit<SvelteKitRemoteForm<Input, Output>, 'for'>;
|
|
108
|
+
/**
|
|
109
|
+
* Form state for buttons and state-aware components.
|
|
110
|
+
* State is derived from context - no result means default or pending,
|
|
111
|
+
* result with no issues means success, issues (via invalid()) means hasIssues.
|
|
112
|
+
* @template T - The type of the form result (defaults to unknown)
|
|
113
|
+
*/
|
|
114
|
+
export type ButtonState<T = unknown> = {
|
|
115
|
+
state: 'default';
|
|
116
|
+
pending: false;
|
|
117
|
+
success: false;
|
|
118
|
+
hasIssues: false;
|
|
119
|
+
result: undefined;
|
|
120
|
+
} | {
|
|
121
|
+
state: 'pending';
|
|
122
|
+
pending: true;
|
|
123
|
+
success: false;
|
|
124
|
+
hasIssues: false;
|
|
125
|
+
result: undefined;
|
|
126
|
+
} | {
|
|
127
|
+
state: 'success';
|
|
128
|
+
pending: false;
|
|
129
|
+
success: true;
|
|
130
|
+
hasIssues: false;
|
|
131
|
+
result: T;
|
|
132
|
+
} | {
|
|
133
|
+
state: 'hasIssues';
|
|
134
|
+
pending: false;
|
|
135
|
+
success: false;
|
|
136
|
+
hasIssues: true;
|
|
137
|
+
result: undefined;
|
|
138
|
+
};
|
|
108
139
|
/**
|
|
109
140
|
* Form context provided by Sform to children.
|
|
110
141
|
* Manages field state (touched, dirty, submitted) for validation display.
|
|
@@ -132,8 +163,14 @@ export interface SformContext {
|
|
|
132
163
|
resetFieldStates: () => void;
|
|
133
164
|
/** Register a field name (called by Sfield on mount) */
|
|
134
165
|
registerField: (name: string) => void;
|
|
166
|
+
/** Register a field that displays its own issues (all except hidden) */
|
|
167
|
+
registerFieldWithIssueDisplay: (name: string) => void;
|
|
135
168
|
/** Programmatically submit the form */
|
|
136
169
|
submitForm: () => void;
|
|
170
|
+
/** Get the current form state (for buttons and state-aware components) */
|
|
171
|
+
getFormState: <T = unknown>() => ButtonState<T>;
|
|
172
|
+
/** Get issues that are not displayed by any Sfield component */
|
|
173
|
+
getUnhandledIssues: () => RemoteFormIssue[];
|
|
137
174
|
}
|
|
138
175
|
/**
|
|
139
176
|
* Enhance callback options - typed based on form Input type.
|
|
@@ -365,8 +402,10 @@ export type SfieldToggleProps = SfieldPropsFrom<ToggleInputProps, boolean, 'togg
|
|
|
365
402
|
export type SfieldToggleOptionsProps = SfieldPropsFrom<ToggleOptionsInputProps, string, 'toggle-options'>;
|
|
366
403
|
/** Props for masked input */
|
|
367
404
|
export type SfieldMaskedProps = SfieldPropsFrom<MaskedInputProps, string, 'masked'>;
|
|
405
|
+
/** Props for hidden input */
|
|
406
|
+
export type SfieldHiddenProps = SfieldPropsFrom<HiddenInputProps, string, 'hidden'>;
|
|
368
407
|
/** All possible Sfield props as a discriminated union */
|
|
369
|
-
type AllSfieldProps = SfieldTextProps | SfieldPasswordProps | SfieldNumberProps | SfieldTextareaProps | SfieldSelectProps | SfieldCheckboxProps | SfieldCheckboxGroupProps | SfieldRadioProps | SfieldRangeProps | SfieldToggleProps | SfieldToggleOptionsProps | SfieldMaskedProps;
|
|
408
|
+
type AllSfieldProps = SfieldTextProps | SfieldPasswordProps | SfieldNumberProps | SfieldTextareaProps | SfieldSelectProps | SfieldCheckboxProps | SfieldCheckboxGroupProps | SfieldRadioProps | SfieldRangeProps | SfieldToggleProps | SfieldToggleOptionsProps | SfieldMaskedProps | SfieldHiddenProps;
|
|
370
409
|
/**
|
|
371
410
|
* Extract props that match a specific field value type.
|
|
372
411
|
* This ensures type="number" is only valid for number fields, etc.
|
|
@@ -515,7 +554,18 @@ export interface RadioInputProps extends BaseInputComponentProps {
|
|
|
515
554
|
options: SelectOption[] | string[];
|
|
516
555
|
}
|
|
517
556
|
/**
|
|
518
|
-
*
|
|
557
|
+
* Props for hidden input component
|
|
558
|
+
*/
|
|
559
|
+
export interface HiddenInputProps {
|
|
560
|
+
/** Remote field from form */
|
|
561
|
+
field: RemoteFormField<RemoteFormFieldValue>;
|
|
562
|
+
/** Field name */
|
|
563
|
+
name: string;
|
|
564
|
+
/** The value for the hidden field - required for hidden inputs */
|
|
565
|
+
value?: string;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* @deprecated Use ButtonState instead
|
|
519
569
|
*/
|
|
520
570
|
export interface ButtonFormState {
|
|
521
571
|
/** Whether form is submitting */
|
|
@@ -527,11 +577,26 @@ export interface ButtonFormState {
|
|
|
527
577
|
/** The form result if available */
|
|
528
578
|
result: unknown;
|
|
529
579
|
}
|
|
580
|
+
/**
|
|
581
|
+
* Minimal form shape for Sbutton type inference.
|
|
582
|
+
* Allows the button to infer the result type T from the form.
|
|
583
|
+
*/
|
|
584
|
+
export interface ButtonFormLike<T = unknown> {
|
|
585
|
+
result?: T;
|
|
586
|
+
pending?: number;
|
|
587
|
+
fields: {
|
|
588
|
+
allIssues?: () => RemoteFormIssue[] | undefined;
|
|
589
|
+
[key: string]: unknown;
|
|
590
|
+
};
|
|
591
|
+
}
|
|
530
592
|
/**
|
|
531
593
|
* Props for button input component
|
|
594
|
+
* @template T - The type of the form result (inferred from form prop)
|
|
532
595
|
*/
|
|
533
|
-
export interface ButtonInputProps {
|
|
534
|
-
/**
|
|
596
|
+
export interface ButtonInputProps<T = unknown> {
|
|
597
|
+
/** The remote form - used to infer the result type T */
|
|
598
|
+
form: ButtonFormLike<T>;
|
|
599
|
+
/** Button text (used if no children snippet provided) */
|
|
535
600
|
label?: string;
|
|
536
601
|
/** Button type */
|
|
537
602
|
buttonType?: 'submit' | 'reset' | 'button';
|
|
@@ -539,16 +604,21 @@ export interface ButtonInputProps {
|
|
|
539
604
|
class?: string;
|
|
540
605
|
/** Whether button is disabled */
|
|
541
606
|
disabled?: boolean;
|
|
542
|
-
/**
|
|
543
|
-
|
|
544
|
-
/**
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
607
|
+
/** Children snippet receives ButtonState<T> for custom rendering with typed result */
|
|
608
|
+
children?: Snippet<[ButtonState<T>]>;
|
|
609
|
+
/** Callback that runs before validation/submission (can be async) */
|
|
610
|
+
onsubmit?: () => void | Promise<void>;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Props for SIssues component
|
|
614
|
+
*/
|
|
615
|
+
export interface SIssuesProps {
|
|
616
|
+
/** General message shown when there are any issues */
|
|
617
|
+
message?: string | Snippet;
|
|
618
|
+
/** CSS class for the wrapper */
|
|
619
|
+
class?: string;
|
|
620
|
+
/** CSS class for the issues list */
|
|
621
|
+
listClass?: string;
|
|
552
622
|
}
|
|
553
623
|
/**
|
|
554
624
|
* Props for range input component
|
|
@@ -612,3 +682,13 @@ export interface MaskedInputProps extends BaseInputComponentProps, InputAffixPro
|
|
|
612
682
|
/** Whether to store the unmasked (raw) value. If true, stores '1234567890'. If false, stores '(123) 456-7890'. Default: true */
|
|
613
683
|
unmaskValue?: boolean;
|
|
614
684
|
}
|
|
685
|
+
/**
|
|
686
|
+
* Props for Fieldset utils component
|
|
687
|
+
*/
|
|
688
|
+
export type FieldsetProps = {
|
|
689
|
+
label?: string;
|
|
690
|
+
labelClass?: string;
|
|
691
|
+
className?: string;
|
|
692
|
+
disabled?: boolean;
|
|
693
|
+
children: Snippet;
|
|
694
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { FieldsetProps } from '../types';
|
|
4
|
+
|
|
5
|
+
let { label, labelClass, className, disabled, children }: FieldsetProps = $props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<fieldset class="sform-checkbox-group {className ?? ''}" {disabled}>
|
|
9
|
+
{#if label}
|
|
10
|
+
<legend class={labelClass}>{label}</legend>
|
|
11
|
+
{/if}
|
|
12
|
+
{@render children()}
|
|
13
|
+
</fieldset>
|
|
14
|
+
|
|
15
|
+
<style>
|
|
16
|
+
.sform-checkbox-group legend {
|
|
17
|
+
padding: 0.25rem 0.5rem;
|
|
18
|
+
margin: 0;
|
|
19
|
+
border: var(--sform-border-width) solid var(--sform-border);
|
|
20
|
+
background: var(--sform-bg);
|
|
21
|
+
border-radius: 0.25rem;
|
|
22
|
+
line-height: 1;
|
|
23
|
+
}
|
|
24
|
+
</style>
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Sform, Sfield, Sbutton } from './Sform/index.js';
|
|
1
|
+
export { Sform, Sfield, Sbutton, SIssues, SResult } from './Sform/index.js';
|
|
2
2
|
export type { ValidateOn, FieldState, SfieldClasses, InputType, SelectOption, SformContext, SformProps, ButtonFormState, ButtonInputProps, InputAffixProps, SfieldTypeMap, AllowedSfieldType, TypedSfieldProps, SfieldBaseProps, TypedBaseSfieldProps, SfieldTextProps, SfieldPasswordProps, SfieldNumberProps, SfieldTextareaProps, SfieldSelectProps, SfieldCheckboxProps, SfieldCheckboxGroupProps, SfieldRadioProps, SfieldRangeProps, SfieldToggleProps, SfieldToggleOptionsProps, SfieldMaskedProps, RemoteForm, RemoteFormField, RemoteFormFields, RemoteFormFieldValue, RemoteFormInput, RemoteFormIssue } from './Sform/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { Sform, Sfield, Sbutton } from './Sform/index.js';
|
|
1
|
+
export { Sform, Sfield, Sbutton, SIssues, SResult } from './Sform/index.js';
|