spaper 1.4.0 → 2.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.
Files changed (206) hide show
  1. package/README.md +20 -59
  2. package/dist/components/Alert.svelte +83 -0
  3. package/dist/components/Alert.svelte.d.ts +15 -0
  4. package/dist/components/Article.svelte +63 -0
  5. package/dist/components/Article.svelte.d.ts +17 -0
  6. package/dist/components/Avatar/Avatar.svelte +102 -0
  7. package/dist/components/Avatar/Avatar.svelte.d.ts +16 -0
  8. package/dist/components/Avatar/AvatarGroup.svelte +21 -0
  9. package/dist/components/Avatar/AvatarGroup.svelte.d.ts +9 -0
  10. package/dist/components/Avatar/index.d.ts +2 -0
  11. package/dist/components/Avatar/index.js +2 -0
  12. package/dist/components/Breadcrumb.svelte +33 -0
  13. package/dist/components/Breadcrumb.svelte.d.ts +12 -0
  14. package/dist/components/Button.svelte +174 -0
  15. package/dist/components/Button.svelte.d.ts +33 -0
  16. package/dist/components/Card.svelte +101 -0
  17. package/dist/components/Card.svelte.d.ts +22 -0
  18. package/dist/components/Carousel/Carousel.svelte +204 -0
  19. package/dist/components/Carousel/Carousel.svelte.d.ts +27 -0
  20. package/dist/components/Carousel/CarouselItem.svelte +48 -0
  21. package/dist/components/Carousel/CarouselItem.svelte.d.ts +7 -0
  22. package/{components → dist/components}/Carousel/index.d.ts +1 -0
  23. package/dist/components/Carousel/types.d.ts +22 -0
  24. package/dist/components/CloseButton.svelte +34 -0
  25. package/dist/components/CloseButton.svelte.d.ts +8 -0
  26. package/dist/components/Collapsible.svelte +64 -0
  27. package/dist/components/Collapsible.svelte.d.ts +16 -0
  28. package/dist/components/CopyButton.svelte +54 -0
  29. package/dist/components/CopyButton.svelte.d.ts +13 -0
  30. package/dist/components/Divider.svelte +9 -0
  31. package/dist/components/Divider.svelte.d.ts +6 -0
  32. package/dist/components/Form/Checkbox.svelte +54 -0
  33. package/dist/components/Form/Checkbox.svelte.d.ts +15 -0
  34. package/dist/components/Form/Input.svelte +105 -0
  35. package/dist/components/Form/Input.svelte.d.ts +21 -0
  36. package/dist/components/Form/NumberInput/DecrementButton.svelte +14 -0
  37. package/dist/components/Form/NumberInput/DecrementButton.svelte.d.ts +9 -0
  38. package/dist/components/Form/NumberInput/IncrementButton.svelte +14 -0
  39. package/dist/components/Form/NumberInput/IncrementButton.svelte.d.ts +9 -0
  40. package/dist/components/Form/NumberInput/NumberInput.svelte +227 -0
  41. package/dist/components/Form/NumberInput/NumberInput.svelte.d.ts +34 -0
  42. package/dist/components/Form/Radio.svelte +42 -0
  43. package/dist/components/Form/Radio.svelte.d.ts +13 -0
  44. package/dist/components/Form/Select.svelte +61 -0
  45. package/dist/components/Form/Select.svelte.d.ts +12 -0
  46. package/dist/components/Form/Slider.svelte +129 -0
  47. package/dist/components/Form/Slider.svelte.d.ts +22 -0
  48. package/dist/components/Form/Switch.svelte +101 -0
  49. package/dist/components/Form/Switch.svelte.d.ts +22 -0
  50. package/dist/components/Form/index.d.ts +9 -0
  51. package/{components → dist/components}/Form/index.js +1 -2
  52. package/dist/components/Hero.svelte +78 -0
  53. package/dist/components/Hero.svelte.d.ts +17 -0
  54. package/dist/components/Icon.svelte +102 -0
  55. package/dist/components/Icon.svelte.d.ts +27 -0
  56. package/dist/components/Modal/Modal.svelte +120 -0
  57. package/dist/components/Modal/Modal.svelte.d.ts +19 -0
  58. package/dist/components/Modal/index.d.ts +12 -0
  59. package/dist/components/Modal/index.js +30 -0
  60. package/dist/components/Navbar.svelte +98 -0
  61. package/dist/components/Navbar.svelte.d.ts +11 -0
  62. package/dist/components/Pagination/Arrow.svelte +29 -0
  63. package/dist/components/Pagination/Arrow.svelte.d.ts +8 -0
  64. package/dist/components/Pagination/NavigationButton.svelte +33 -0
  65. package/dist/components/Pagination/NavigationButton.svelte.d.ts +13 -0
  66. package/dist/components/Pagination/Pagination.svelte +209 -0
  67. package/dist/components/Pagination/Pagination.svelte.d.ts +32 -0
  68. package/{components → dist/components}/Pagination/arrow-dimension.js +3 -3
  69. package/{components → dist/components}/Pagination/index.d.ts +1 -1
  70. package/dist/components/Popover.svelte +64 -0
  71. package/dist/components/Popover.svelte.d.ts +17 -0
  72. package/dist/components/Progress.svelte +87 -0
  73. package/dist/components/Progress.svelte.d.ts +19 -0
  74. package/dist/components/ScrollTop.svelte +79 -0
  75. package/dist/components/ScrollTop.svelte.d.ts +17 -0
  76. package/dist/components/Skeleton.svelte +104 -0
  77. package/dist/components/Skeleton.svelte.d.ts +21 -0
  78. package/dist/components/Spinner.svelte +59 -0
  79. package/dist/components/Spinner.svelte.d.ts +16 -0
  80. package/dist/components/Table/Table.svelte +292 -0
  81. package/dist/components/Table/Table.svelte.d.ts +25 -0
  82. package/dist/components/Table/TableColumn.svelte +62 -0
  83. package/dist/components/Table/TableColumn.svelte.d.ts +15 -0
  84. package/dist/components/Table/context.d.ts +13 -0
  85. package/dist/components/Table/context.js +1 -0
  86. package/dist/components/Table/index.d.ts +2 -0
  87. package/dist/components/Table/index.js +2 -0
  88. package/dist/components/Tabs/Tab.svelte +90 -0
  89. package/dist/components/Tabs/Tab.svelte.d.ts +14 -0
  90. package/dist/components/Tabs/Tabs.svelte +138 -0
  91. package/dist/components/Tabs/Tabs.svelte.d.ts +13 -0
  92. package/{components → dist/components}/Tabs/utils.d.ts +4 -3
  93. package/dist/components/Tag.svelte +38 -0
  94. package/dist/components/Tag.svelte.d.ts +10 -0
  95. package/dist/components/Toast/Toast.svelte +105 -0
  96. package/dist/components/Toast/Toast.svelte.d.ts +6 -0
  97. package/dist/components/Toast/ToastContainer.svelte +101 -0
  98. package/dist/components/Toast/ToastContainer.svelte.d.ts +8 -0
  99. package/{components → dist/components}/Toast/index.d.ts +19 -5
  100. package/dist/components/Toast/index.js +100 -0
  101. package/dist/icons.d.ts +3 -0
  102. package/dist/icons.js +2 -0
  103. package/dist/index.d.ts +31 -0
  104. package/{index.js → dist/index.js} +10 -5
  105. package/dist/type-icons.d.ts +4 -0
  106. package/dist/type-icons.js +9 -0
  107. package/dist/types.d.ts +29 -0
  108. package/dist/utils.d.ts +16 -0
  109. package/dist/utils.js +44 -0
  110. package/package.json +70 -68
  111. package/components/Alert.svelte +0 -34
  112. package/components/Alert.svelte.d.ts +0 -21
  113. package/components/Article.svelte +0 -39
  114. package/components/Article.svelte.d.ts +0 -26
  115. package/components/Badge.svelte +0 -16
  116. package/components/Badge.svelte.d.ts +0 -20
  117. package/components/Breadcrumb.svelte +0 -17
  118. package/components/Breadcrumb.svelte.d.ts +0 -21
  119. package/components/Button.svelte +0 -41
  120. package/components/Button.svelte.d.ts +0 -30
  121. package/components/Card.svelte +0 -70
  122. package/components/Card.svelte.d.ts +0 -32
  123. package/components/Carousel/Carousel.svelte +0 -128
  124. package/components/Carousel/Carousel.svelte.d.ts +0 -35
  125. package/components/Carousel/CarouselItem.svelte +0 -32
  126. package/components/Carousel/CarouselItem.svelte.d.ts +0 -18
  127. package/components/Carousel/types.d.ts +0 -14
  128. package/components/CloseButton.svelte +0 -23
  129. package/components/CloseButton.svelte.d.ts +0 -19
  130. package/components/Collapsible.svelte +0 -49
  131. package/components/Collapsible.svelte.d.ts +0 -21
  132. package/components/CopyButton.svelte +0 -43
  133. package/components/CopyButton.svelte.d.ts +0 -24
  134. package/components/Form/Checkbox.svelte +0 -37
  135. package/components/Form/Checkbox.svelte.d.ts +0 -26
  136. package/components/Form/Form.svelte +0 -22
  137. package/components/Form/Form.svelte.d.ts +0 -26
  138. package/components/Form/Input.svelte +0 -67
  139. package/components/Form/Input.svelte.d.ts +0 -28
  140. package/components/Form/NumberInput/DecrementButton.svelte +0 -9
  141. package/components/Form/NumberInput/DecrementButton.svelte.d.ts +0 -19
  142. package/components/Form/NumberInput/IncrementButton.svelte +0 -9
  143. package/components/Form/NumberInput/IncrementButton.svelte.d.ts +0 -19
  144. package/components/Form/NumberInput/NumberInput.svelte +0 -129
  145. package/components/Form/NumberInput/NumberInput.svelte.d.ts +0 -36
  146. package/components/Form/Radio.svelte +0 -26
  147. package/components/Form/Radio.svelte.d.ts +0 -25
  148. package/components/Form/Select.svelte +0 -40
  149. package/components/Form/Select.svelte.d.ts +0 -24
  150. package/components/Form/Slider.svelte +0 -124
  151. package/components/Form/Slider.svelte.d.ts +0 -30
  152. package/components/Form/Switch.svelte +0 -71
  153. package/components/Form/index.d.ts +0 -10
  154. package/components/Form/style.scss +0 -4
  155. package/components/Hero.svelte +0 -78
  156. package/components/Hero.svelte.d.ts +0 -26
  157. package/components/Layout/Col.svelte +0 -25
  158. package/components/Layout/Col.svelte.d.ts +0 -27
  159. package/components/Layout/Row.svelte +0 -24
  160. package/components/Layout/Row.svelte.d.ts +0 -26
  161. package/components/Layout/index.d.ts +0 -2
  162. package/components/Layout/index.js +0 -2
  163. package/components/Modal/Modal.svelte +0 -62
  164. package/components/Modal/Modal.svelte.d.ts +0 -28
  165. package/components/Modal/index.d.ts +0 -13
  166. package/components/Modal/index.js +0 -17
  167. package/components/Navbar.svelte +0 -40
  168. package/components/Navbar.svelte.d.ts +0 -22
  169. package/components/Pagination/Arrow.svelte +0 -17
  170. package/components/Pagination/Arrow.svelte.d.ts +0 -19
  171. package/components/Pagination/NavigationButton.svelte +0 -23
  172. package/components/Pagination/NavigationButton.svelte.d.ts +0 -23
  173. package/components/Pagination/Pagination.svelte +0 -137
  174. package/components/Pagination/Pagination.svelte.d.ts +0 -36
  175. package/components/Popover.svelte +0 -62
  176. package/components/Popover.svelte.d.ts +0 -25
  177. package/components/Progress.svelte +0 -39
  178. package/components/Progress.svelte.d.ts +0 -25
  179. package/components/Skeleton.svelte +0 -55
  180. package/components/Skeleton.svelte.d.ts +0 -22
  181. package/components/Table.svelte +0 -73
  182. package/components/Table.svelte.d.ts +0 -24
  183. package/components/Tabs/Tab.svelte +0 -52
  184. package/components/Tabs/Tab.svelte.d.ts +0 -20
  185. package/components/Tabs/Tabs.svelte +0 -90
  186. package/components/Tabs/Tabs.svelte.d.ts +0 -25
  187. package/components/Toast/Toast.svelte +0 -91
  188. package/components/Toast/Toast.svelte.d.ts +0 -26
  189. package/components/Toast/ToastContainer.svelte +0 -37
  190. package/components/Toast/ToastContainer.svelte.d.ts +0 -18
  191. package/components/Toast/index.js +0 -37
  192. package/index.d.ts +0 -23
  193. package/types.d.ts +0 -16
  194. package/utils.d.ts +0 -16
  195. package/utils.js +0 -34
  196. /package/{components → dist/components}/Carousel/index.js +0 -0
  197. /package/{components → dist/components}/Carousel/types.js +0 -0
  198. /package/{components → dist/components}/Form/NumberInput/index.d.ts +0 -0
  199. /package/{components → dist/components}/Form/NumberInput/index.js +0 -0
  200. /package/{components → dist/components}/Pagination/arrow-dimension.d.ts +0 -0
  201. /package/{components → dist/components}/Pagination/index.js +0 -0
  202. /package/{components → dist/components}/Tabs/index.d.ts +0 -0
  203. /package/{components → dist/components}/Tabs/index.js +0 -0
  204. /package/{components → dist/components}/Tabs/utils.js +0 -0
  205. /package/{components → dist/components}/style.scss +0 -0
  206. /package/{types.js → dist/types.js} +0 -0
@@ -0,0 +1,54 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ label?: string
4
+ value?: string
5
+ name?: string
6
+ group?: string[]
7
+ checked?: boolean
8
+ disabled?: boolean
9
+ onchange?: (checked: boolean) => void
10
+ onfocus?: (e: FocusEvent) => void
11
+ onblur?: (e: FocusEvent) => void
12
+ [key: string]: any
13
+ }
14
+
15
+ let {
16
+ label = '',
17
+ value = '',
18
+ name = '',
19
+ group = $bindable([]),
20
+ checked = $bindable(false),
21
+ disabled = false,
22
+ onchange,
23
+ onfocus,
24
+ onblur,
25
+ ...rest
26
+ }: Props = $props()
27
+
28
+ function handleChange({ target }: Event) {
29
+ const el = target as HTMLInputElement
30
+ const { value: nextValue, checked: nextChecked } = el
31
+ checked = nextChecked
32
+ if (nextChecked) {
33
+ group = [...group, nextValue]
34
+ } else {
35
+ group = group.filter((item) => item !== nextValue)
36
+ }
37
+
38
+ onchange?.(checked)
39
+ }
40
+ </script>
41
+
42
+ <label {...rest} class={['paper-check', rest.class]}>
43
+ <input
44
+ type="checkbox"
45
+ {value}
46
+ {name}
47
+ {disabled}
48
+ checked={group.includes(value) || checked}
49
+ {onfocus}
50
+ {onblur}
51
+ onchange={handleChange}
52
+ />
53
+ <span>{label}</span>
54
+ </label>
@@ -0,0 +1,15 @@
1
+ interface Props {
2
+ label?: string;
3
+ value?: string;
4
+ name?: string;
5
+ group?: string[];
6
+ checked?: boolean;
7
+ disabled?: boolean;
8
+ onchange?: (checked: boolean) => void;
9
+ onfocus?: (e: FocusEvent) => void;
10
+ onblur?: (e: FocusEvent) => void;
11
+ [key: string]: any;
12
+ }
13
+ declare const Checkbox: import("svelte").Component<Props, {}, "group" | "checked">;
14
+ type Checkbox = ReturnType<typeof Checkbox>;
15
+ export default Checkbox;
@@ -0,0 +1,105 @@
1
+ <script lang="ts">
2
+ import { getDomAttributes } from '../../utils'
3
+ import type { InputType } from './'
4
+ import type { Attributes } from '../../types'
5
+
6
+ interface Props {
7
+ label?: string
8
+ value?: string
9
+ /** @deprecated Use `class="w-full"` instead. */
10
+ block?: boolean
11
+ type?: InputType
12
+ /** Receives the value and returns `true` if it is valid. */
13
+ valid?: ((val: string) => boolean) | null
14
+ /** For textarea, does not allow resizing. */
15
+ noResize?: boolean
16
+ class?: string
17
+ oninput?: (value: string) => void
18
+ onfocus?: (e: FocusEvent) => void
19
+ onblur?: (e: FocusEvent) => void
20
+ onchange?: (e: Event) => void
21
+ [key: string]: unknown
22
+ }
23
+
24
+ let {
25
+ label = '',
26
+ value = $bindable(''),
27
+ block = false,
28
+ type = 'text',
29
+ valid = null,
30
+ noResize = false,
31
+ class: className = '',
32
+ oninput,
33
+ onfocus,
34
+ onblur,
35
+ onchange,
36
+ ...rest
37
+ }: Props = $props()
38
+
39
+ const isTextarea = $derived(type === 'textarea')
40
+ const isValid = $derived(valid ? valid(value) : true)
41
+
42
+ const classes = $derived([
43
+ isTextarea ? 'textarea-paper' : 'input-paper',
44
+ {
45
+ 'w-full': block,
46
+ 'border-danger': !isTextarea && !isValid && !!value,
47
+ 'border-success': !isTextarea && isValid && !!value && !!valid,
48
+ 'resize-none': isTextarea && noResize,
49
+ },
50
+ className,
51
+ ])
52
+
53
+ const attr: Attributes = $derived(
54
+ getDomAttributes({
55
+ props: { ...rest, type },
56
+ classes: '',
57
+ toOmit: [
58
+ 'block',
59
+ 'value',
60
+ 'valid',
61
+ 'noResize',
62
+ 'label',
63
+ 'oninput',
64
+ 'onfocus',
65
+ 'onblur',
66
+ 'onchange',
67
+ ],
68
+ }),
69
+ )
70
+
71
+ function handleInput(e: Event) {
72
+ const target = e.target as HTMLInputElement | HTMLTextAreaElement
73
+ oninput?.(target.value)
74
+ }
75
+ </script>
76
+
77
+ {#snippet field()}
78
+ <input
79
+ {...attr}
80
+ class={classes}
81
+ bind:value
82
+ oninput={handleInput}
83
+ {onfocus}
84
+ {onblur}
85
+ {onchange}
86
+ />
87
+ {/snippet}
88
+
89
+ {#if isTextarea}
90
+ <textarea
91
+ {...attr}
92
+ class={classes}
93
+ bind:value
94
+ oninput={handleInput}
95
+ {onfocus}
96
+ {onblur}
97
+ {onchange}></textarea>
98
+ {:else if label}
99
+ <label>
100
+ {label}
101
+ {@render field()}
102
+ </label>
103
+ {:else}
104
+ {@render field()}
105
+ {/if}
@@ -0,0 +1,21 @@
1
+ import type { InputType } from './';
2
+ interface Props {
3
+ label?: string;
4
+ value?: string;
5
+ /** @deprecated Use `class="w-full"` instead. */
6
+ block?: boolean;
7
+ type?: InputType;
8
+ /** Receives the value and returns `true` if it is valid. */
9
+ valid?: ((val: string) => boolean) | null;
10
+ /** For textarea, does not allow resizing. */
11
+ noResize?: boolean;
12
+ class?: string;
13
+ oninput?: (value: string) => void;
14
+ onfocus?: (e: FocusEvent) => void;
15
+ onblur?: (e: FocusEvent) => void;
16
+ onchange?: (e: Event) => void;
17
+ [key: string]: unknown;
18
+ }
19
+ declare const Input: import("svelte").Component<Props, {}, "value">;
20
+ type Input = ReturnType<typeof Input>;
21
+ export default Input;
@@ -0,0 +1,14 @@
1
+ <script lang="ts">
2
+ import type { PaperType } from '../../../types'
3
+ import Button from '../../Button.svelte'
4
+
5
+ interface Props {
6
+ clickHandler: (e: MouseEvent) => any
7
+ type: PaperType
8
+ [key: string]: any
9
+ }
10
+
11
+ let { clickHandler, type, ...rest }: Props = $props()
12
+ </script>
13
+
14
+ <Button {...rest} {type} onclick={clickHandler}>-</Button>
@@ -0,0 +1,9 @@
1
+ import type { PaperType } from '../../../types';
2
+ interface Props {
3
+ clickHandler: (e: MouseEvent) => any;
4
+ type: PaperType;
5
+ [key: string]: any;
6
+ }
7
+ declare const DecrementButton: import("svelte").Component<Props, {}, "">;
8
+ type DecrementButton = ReturnType<typeof DecrementButton>;
9
+ export default DecrementButton;
@@ -0,0 +1,14 @@
1
+ <script lang="ts">
2
+ import type { PaperType } from '../../../types'
3
+ import Button from '../../Button.svelte'
4
+
5
+ interface Props {
6
+ clickHandler: (e: MouseEvent) => any
7
+ type: PaperType
8
+ [key: string]: any
9
+ }
10
+
11
+ let { clickHandler, type, ...rest }: Props = $props()
12
+ </script>
13
+
14
+ <Button {...rest} {type} onclick={clickHandler}>+</Button>
@@ -0,0 +1,9 @@
1
+ import type { PaperType } from '../../../types';
2
+ interface Props {
3
+ clickHandler: (e: MouseEvent) => any;
4
+ type: PaperType;
5
+ [key: string]: any;
6
+ }
7
+ declare const IncrementButton: import("svelte").Component<Props, {}, "">;
8
+ type IncrementButton = ReturnType<typeof IncrementButton>;
9
+ export default IncrementButton;
@@ -0,0 +1,227 @@
1
+ <script lang="ts">
2
+ import { DecrementButton, IncrementButton } from './'
3
+ import { getDomAttributes } from '../../../utils'
4
+ import type { Attributes, PaperType } from '../../../types'
5
+
6
+ interface Props {
7
+ label?: string
8
+ value?: number | null
9
+ step?: number
10
+ min?: number | null
11
+ max?: number | null
12
+ disabled?: boolean
13
+ controls?: boolean
14
+ controlsType?: PaperType
15
+ /** @deprecated Use `class="w-full"` instead. */
16
+ block?: boolean
17
+ /** Receives the value and returns `true` if it is valid. */
18
+ valid?: ((val: number | null) => boolean) | null
19
+ prefix?: string
20
+ suffix?: string
21
+ /**
22
+ * Either an `Intl` locale, or a function that receives the value and returns
23
+ * the text. `"locale"` uses the browser locale. Any other string is a locale
24
+ * tag (`"fr-FR"`).
25
+ */
26
+ format?: string | ((val: number | null) => string) | null
27
+ /** Passed to `Intl.NumberFormat` when `format` is a locale string. */
28
+ formatOptions?: Intl.NumberFormatOptions
29
+ class?: string
30
+ oninput?: (value: string) => void
31
+ onfocus?: (e: FocusEvent) => void
32
+ onblur?: (e: FocusEvent) => void
33
+ onchange?: (e: Event) => void
34
+ [key: string]: unknown
35
+ }
36
+
37
+ let {
38
+ label = '',
39
+ value = $bindable(null),
40
+ step = 1,
41
+ min = null,
42
+ max = null,
43
+ disabled = false,
44
+ controls = true,
45
+ controlsType = 'secondary',
46
+ block = false,
47
+ valid = null,
48
+ prefix = '',
49
+ suffix = '',
50
+ format = null,
51
+ formatOptions = undefined,
52
+ class: className = '',
53
+ oninput,
54
+ onfocus,
55
+ onblur,
56
+ onchange,
57
+ ...rest
58
+ }: Props = $props()
59
+
60
+ const isValid = $derived(valid ? valid(value) : true)
61
+
62
+ const classes = $derived([
63
+ 'input-paper',
64
+ {
65
+ 'w-full': block,
66
+ 'border-danger': !isValid && value !== null,
67
+ 'border-success': isValid && value !== null && !!valid,
68
+ },
69
+ className,
70
+ ])
71
+
72
+ const attr: Attributes = $derived(
73
+ getDomAttributes({
74
+ props: { ...rest, disabled },
75
+ classes: '',
76
+ toOmit: [
77
+ 'block',
78
+ 'value',
79
+ 'valid',
80
+ 'noResize',
81
+ 'min',
82
+ 'max',
83
+ 'label',
84
+ 'step',
85
+ 'controls',
86
+ 'controlsType',
87
+ 'prefix',
88
+ 'suffix',
89
+ 'format',
90
+ 'formatOptions',
91
+ 'oninput',
92
+ 'onfocus',
93
+ 'onblur',
94
+ 'onchange',
95
+ ],
96
+ }),
97
+ )
98
+
99
+ const canDecrement = $derived(
100
+ !disabled && (min !== null && value !== null ? value - step >= min : true),
101
+ )
102
+ const canIncrement = $derived(
103
+ !disabled && (max !== null && value !== null ? value + step <= max : true),
104
+ )
105
+
106
+ const formattedValue = $derived.by(() => {
107
+ if (value === null) return ''
108
+
109
+ let next = String(value)
110
+
111
+ if (format) {
112
+ if (typeof format === 'string') {
113
+ next = new Intl.NumberFormat(
114
+ format === 'locale' ? undefined : format,
115
+ formatOptions,
116
+ ).format(value)
117
+ } else {
118
+ next = format(value)
119
+ }
120
+ }
121
+
122
+ return [prefix, next, suffix].join(' ').trim()
123
+ })
124
+
125
+ function parseInput(raw: string): number | null {
126
+ let text = raw.trim()
127
+ if (prefix && text.startsWith(prefix)) text = text.slice(prefix.length).trim()
128
+ if (suffix && text.endsWith(suffix))
129
+ text = text.slice(0, -suffix.length).trim()
130
+ text = text.replace(/\s/g, '')
131
+ if (text === '' || text === '-' || text === '.' || text === '-.') return null
132
+ const n = Number(text)
133
+ return Number.isFinite(n) ? n : null
134
+ }
135
+
136
+ function clamp(n: number) {
137
+ if (max !== null && n > max) return max
138
+ if (min !== null && n < min) return min
139
+ return n
140
+ }
141
+
142
+ function commit(target: HTMLInputElement) {
143
+ const n = parseInput(target.value)
144
+ if (n === null) {
145
+ target.value = formattedValue
146
+ return
147
+ }
148
+ value = clamp(n)
149
+ target.value = formattedValue
150
+ }
151
+
152
+ function handleInput(e: Event) {
153
+ const target = e.target as HTMLInputElement
154
+ oninput?.(target.value)
155
+ const n = parseInput(target.value)
156
+ if (n !== null && max !== null && n > max) commit(target)
157
+ }
158
+
159
+ function handleBlur(e: FocusEvent) {
160
+ commit(e.currentTarget as HTMLInputElement)
161
+ onblur?.(e)
162
+ }
163
+
164
+ function stepBy(direction: 1 | -1) {
165
+ if (disabled || value === null) return
166
+ if (direction === 1 && !canIncrement) return
167
+ if (direction === -1 && !canDecrement) return
168
+ value += direction * step
169
+ }
170
+
171
+ function handleKeydown(e: KeyboardEvent) {
172
+ if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') return
173
+ e.preventDefault()
174
+ stepBy(e.key === 'ArrowUp' ? 1 : -1)
175
+ }
176
+ </script>
177
+
178
+ <div class="flex gap-1">
179
+ {#if controls}
180
+ <DecrementButton
181
+ class="self-end! p-2!"
182
+ clickHandler={() => {
183
+ if (value !== null) value -= step
184
+ }}
185
+ type={controlsType}
186
+ disabled={!canDecrement}
187
+ />
188
+ {/if}
189
+
190
+ {#snippet field()}
191
+ <input
192
+ {...attr}
193
+ class={classes}
194
+ inputmode="numeric"
195
+ role="spinbutton"
196
+ value={formattedValue}
197
+ aria-valuemin={min ?? undefined}
198
+ aria-valuemax={max ?? undefined}
199
+ aria-valuenow={value ?? undefined}
200
+ onkeydown={handleKeydown}
201
+ oninput={handleInput}
202
+ {onfocus}
203
+ onblur={handleBlur}
204
+ {onchange}
205
+ />
206
+ {/snippet}
207
+
208
+ {#if label}
209
+ <label>
210
+ {label}
211
+ {@render field()}
212
+ </label>
213
+ {:else}
214
+ {@render field()}
215
+ {/if}
216
+
217
+ {#if controls}
218
+ <IncrementButton
219
+ class="self-end! p-2!"
220
+ clickHandler={() => {
221
+ if (value !== null) value += step
222
+ }}
223
+ type={controlsType}
224
+ disabled={!canIncrement}
225
+ />
226
+ {/if}
227
+ </div>
@@ -0,0 +1,34 @@
1
+ import type { PaperType } from '../../../types';
2
+ interface Props {
3
+ label?: string;
4
+ value?: number | null;
5
+ step?: number;
6
+ min?: number | null;
7
+ max?: number | null;
8
+ disabled?: boolean;
9
+ controls?: boolean;
10
+ controlsType?: PaperType;
11
+ /** @deprecated Use `class="w-full"` instead. */
12
+ block?: boolean;
13
+ /** Receives the value and returns `true` if it is valid. */
14
+ valid?: ((val: number | null) => boolean) | null;
15
+ prefix?: string;
16
+ suffix?: string;
17
+ /**
18
+ * Either an `Intl` locale, or a function that receives the value and returns
19
+ * the text. `"locale"` uses the browser locale. Any other string is a locale
20
+ * tag (`"fr-FR"`).
21
+ */
22
+ format?: string | ((val: number | null) => string) | null;
23
+ /** Passed to `Intl.NumberFormat` when `format` is a locale string. */
24
+ formatOptions?: Intl.NumberFormatOptions;
25
+ class?: string;
26
+ oninput?: (value: string) => void;
27
+ onfocus?: (e: FocusEvent) => void;
28
+ onblur?: (e: FocusEvent) => void;
29
+ onchange?: (e: Event) => void;
30
+ [key: string]: unknown;
31
+ }
32
+ declare const NumberInput: import("svelte").Component<Props, {}, "value">;
33
+ type NumberInput = ReturnType<typeof NumberInput>;
34
+ export default NumberInput;
@@ -0,0 +1,42 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ label?: string
4
+ value?: string
5
+ group?: string
6
+ onfocus?: (e: FocusEvent) => void
7
+ onblur?: (e: FocusEvent) => void
8
+ onchange?: (e: Event) => void
9
+ children?: import('svelte').Snippet
10
+ [key: string]: any
11
+ }
12
+
13
+ let {
14
+ label = '',
15
+ value = '',
16
+ group = $bindable(''),
17
+ onfocus,
18
+ onblur,
19
+ onchange,
20
+ children,
21
+ ...rest
22
+ }: Props = $props()
23
+ </script>
24
+
25
+ <label class="paper-radio">
26
+ <input
27
+ type="radio"
28
+ {value}
29
+ {...rest}
30
+ bind:group
31
+ {onfocus}
32
+ {onblur}
33
+ {onchange}
34
+ />
35
+ <span>
36
+ {#if children}
37
+ {@render children?.()}
38
+ {:else}
39
+ {label}
40
+ {/if}
41
+ </span>
42
+ </label>
@@ -0,0 +1,13 @@
1
+ interface Props {
2
+ label?: string;
3
+ value?: string;
4
+ group?: string;
5
+ onfocus?: (e: FocusEvent) => void;
6
+ onblur?: (e: FocusEvent) => void;
7
+ onchange?: (e: Event) => void;
8
+ children?: import('svelte').Snippet;
9
+ [key: string]: any;
10
+ }
11
+ declare const Radio: import("svelte").Component<Props, {}, "group">;
12
+ type Radio = ReturnType<typeof Radio>;
13
+ export default Radio;
@@ -0,0 +1,61 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ label?: string
4
+ value?: string
5
+ onchange?: (value: string) => void
6
+ onblur?: (e: FocusEvent) => void
7
+ onfocus?: (e: FocusEvent) => void
8
+ children?: import('svelte').Snippet
9
+ [key: string]: any
10
+ }
11
+
12
+ let {
13
+ label = '',
14
+ value = $bindable(''),
15
+ onchange,
16
+ onblur,
17
+ onfocus,
18
+ children,
19
+ ...rest
20
+ }: Props = $props()
21
+
22
+ let selectElement: HTMLSelectElement | undefined = $state()
23
+
24
+ function handleChange({ target }: Event) {
25
+ onchange?.((target as HTMLSelectElement).value)
26
+ }
27
+
28
+ $effect(() => {
29
+ if (selectElement && value !== undefined) {
30
+ const options = selectElement.querySelectorAll('option')
31
+ const opt = Array.from(options).find((opt: HTMLOptionElement) => {
32
+ return opt.value == value
33
+ })
34
+
35
+ if (opt) opt.selected = true
36
+ }
37
+ })
38
+ </script>
39
+
40
+ {#snippet field()}
41
+ <select
42
+ bind:this={selectElement}
43
+ bind:value
44
+ {...rest}
45
+ class={['select-paper', rest.class]}
46
+ onchange={handleChange}
47
+ {onblur}
48
+ {onfocus}
49
+ >
50
+ {@render children?.()}
51
+ </select>
52
+ {/snippet}
53
+
54
+ {#if label}
55
+ <label>
56
+ {label}
57
+ {@render field()}
58
+ </label>
59
+ {:else}
60
+ {@render field()}
61
+ {/if}
@@ -0,0 +1,12 @@
1
+ interface Props {
2
+ label?: string;
3
+ value?: string;
4
+ onchange?: (value: string) => void;
5
+ onblur?: (e: FocusEvent) => void;
6
+ onfocus?: (e: FocusEvent) => void;
7
+ children?: import('svelte').Snippet;
8
+ [key: string]: any;
9
+ }
10
+ declare const Select: import("svelte").Component<Props, {}, "value">;
11
+ type Select = ReturnType<typeof Select>;
12
+ export default Select;