@simplysm/solid 13.0.84 → 13.0.86

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 (180) hide show
  1. package/README.md +143 -28
  2. package/dist/components/data/list/ListItem.d.ts.map +1 -1
  3. package/dist/components/data/list/ListItem.js +11 -4
  4. package/dist/components/data/list/ListItem.js.map +2 -2
  5. package/dist/components/data/list/ListItem.styles.d.ts +2 -0
  6. package/dist/components/data/list/ListItem.styles.d.ts.map +1 -1
  7. package/dist/components/data/list/ListItem.styles.js +11 -1
  8. package/dist/components/data/list/ListItem.styles.js.map +1 -1
  9. package/dist/components/data/sheet/DataSheet.d.ts.map +1 -1
  10. package/dist/components/data/sheet/DataSheet.js +6 -9
  11. package/dist/components/data/sheet/DataSheet.js.map +2 -2
  12. package/dist/components/data/sheet/hooks/createDataSheetExpansion.d.ts.map +1 -1
  13. package/dist/components/data/sheet/hooks/createDataSheetExpansion.js +15 -17
  14. package/dist/components/data/sheet/hooks/createDataSheetExpansion.js.map +1 -1
  15. package/dist/components/data/sheet/hooks/createDataSheetReorder.d.ts.map +1 -1
  16. package/dist/components/data/sheet/hooks/createDataSheetReorder.js +12 -12
  17. package/dist/components/data/sheet/hooks/createDataSheetReorder.js.map +1 -1
  18. package/dist/components/data/sheet/hooks/createDataSheetSelection.d.ts.map +1 -1
  19. package/dist/components/data/sheet/hooks/createDataSheetSelection.js +9 -3
  20. package/dist/components/data/sheet/hooks/createDataSheetSelection.js.map +1 -1
  21. package/dist/components/disclosure/Dialog.d.ts.map +1 -1
  22. package/dist/components/disclosure/Dialog.js +3 -21
  23. package/dist/components/disclosure/Dialog.js.map +2 -2
  24. package/dist/components/disclosure/Dropdown.d.ts.map +1 -1
  25. package/dist/components/disclosure/Dropdown.js +1 -11
  26. package/dist/components/disclosure/Dropdown.js.map +2 -2
  27. package/dist/components/disclosure/Tabs.d.ts.map +1 -1
  28. package/dist/components/disclosure/Tabs.js +1 -3
  29. package/dist/components/disclosure/Tabs.js.map +2 -2
  30. package/dist/components/features/crud-detail/CrudDetail.js +103 -102
  31. package/dist/components/features/crud-detail/CrudDetail.js.map +2 -2
  32. package/dist/components/features/crud-sheet/CrudSheet.d.ts.map +1 -1
  33. package/dist/components/features/crud-sheet/CrudSheet.js +10 -5
  34. package/dist/components/features/crud-sheet/CrudSheet.js.map +2 -2
  35. package/dist/components/features/data-select-button/DataSelectButton.d.ts.map +1 -1
  36. package/dist/components/features/data-select-button/DataSelectButton.js +30 -26
  37. package/dist/components/features/data-select-button/DataSelectButton.js.map +2 -2
  38. package/dist/components/features/permission-table/PermissionTable.js +5 -1
  39. package/dist/components/features/permission-table/PermissionTable.js.map +2 -2
  40. package/dist/components/feedback/busy/BusyContainer.d.ts.map +1 -1
  41. package/dist/components/feedback/busy/BusyContainer.js +1 -6
  42. package/dist/components/feedback/busy/BusyContainer.js.map +2 -2
  43. package/dist/components/form-control/DropdownTrigger.styles.js +1 -1
  44. package/dist/components/form-control/checkbox/SelectableBase.d.ts.map +1 -1
  45. package/dist/components/form-control/checkbox/SelectableBase.js +2 -4
  46. package/dist/components/form-control/checkbox/SelectableBase.js.map +2 -2
  47. package/dist/components/form-control/combobox/Combobox.d.ts +19 -5
  48. package/dist/components/form-control/combobox/Combobox.d.ts.map +1 -1
  49. package/dist/components/form-control/combobox/Combobox.js +2 -4
  50. package/dist/components/form-control/combobox/Combobox.js.map +1 -1
  51. package/dist/components/form-control/date-range-picker/DateRangePicker.d.ts +2 -2
  52. package/dist/components/form-control/date-range-picker/DateRangePicker.d.ts.map +1 -1
  53. package/dist/components/form-control/date-range-picker/DateRangePicker.js +11 -3
  54. package/dist/components/form-control/date-range-picker/DateRangePicker.js.map +2 -2
  55. package/dist/components/form-control/editor/RichTextEditor.d.ts +2 -2
  56. package/dist/components/form-control/editor/RichTextEditor.d.ts.map +1 -1
  57. package/dist/components/form-control/editor/RichTextEditor.js +2 -4
  58. package/dist/components/form-control/editor/RichTextEditor.js.map +2 -2
  59. package/dist/components/form-control/field/DatePicker.d.ts +2 -2
  60. package/dist/components/form-control/field/DatePicker.d.ts.map +1 -1
  61. package/dist/components/form-control/field/DatePicker.js.map +1 -1
  62. package/dist/components/form-control/field/DateTimePicker.d.ts +2 -2
  63. package/dist/components/form-control/field/DateTimePicker.d.ts.map +1 -1
  64. package/dist/components/form-control/field/DateTimePicker.js.map +1 -1
  65. package/dist/components/form-control/field/Field.styles.d.ts +6 -7
  66. package/dist/components/form-control/field/Field.styles.d.ts.map +1 -1
  67. package/dist/components/form-control/field/Field.styles.js.map +1 -1
  68. package/dist/components/form-control/field/NumberInput.d.ts +2 -2
  69. package/dist/components/form-control/field/NumberInput.d.ts.map +1 -1
  70. package/dist/components/form-control/field/NumberInput.js +7 -7
  71. package/dist/components/form-control/field/NumberInput.js.map +2 -2
  72. package/dist/components/form-control/field/TextInput.d.ts +2 -2
  73. package/dist/components/form-control/field/TextInput.d.ts.map +1 -1
  74. package/dist/components/form-control/field/TextInput.js.map +1 -1
  75. package/dist/components/form-control/field/Textarea.d.ts +2 -2
  76. package/dist/components/form-control/field/Textarea.d.ts.map +1 -1
  77. package/dist/components/form-control/field/Textarea.js +1 -3
  78. package/dist/components/form-control/field/Textarea.js.map +2 -2
  79. package/dist/components/form-control/field/TimePicker.d.ts +2 -2
  80. package/dist/components/form-control/field/TimePicker.d.ts.map +1 -1
  81. package/dist/components/form-control/field/TimePicker.js.map +1 -1
  82. package/dist/components/form-control/numpad/Numpad.d.ts.map +1 -1
  83. package/dist/components/form-control/numpad/Numpad.js +4 -17
  84. package/dist/components/form-control/numpad/Numpad.js.map +2 -2
  85. package/dist/components/form-control/select/Select.d.ts +2 -0
  86. package/dist/components/form-control/select/Select.d.ts.map +1 -1
  87. package/dist/components/form-control/select/Select.js +29 -15
  88. package/dist/components/form-control/select/Select.js.map +2 -2
  89. package/dist/components/form-control/state-preset/StatePreset.d.ts +1 -3
  90. package/dist/components/form-control/state-preset/StatePreset.d.ts.map +1 -1
  91. package/dist/components/form-control/state-preset/StatePreset.js +69 -95
  92. package/dist/components/form-control/state-preset/StatePreset.js.map +2 -2
  93. package/dist/components/layout/FormGroup.js +1 -1
  94. package/dist/components/layout/FormGroup.js.map +1 -1
  95. package/dist/components/layout/FormTable.js +3 -3
  96. package/dist/components/layout/FormTable.js.map +1 -1
  97. package/dist/components/layout/sidebar/Sidebar.d.ts.map +1 -1
  98. package/dist/components/layout/sidebar/Sidebar.js +3 -6
  99. package/dist/components/layout/sidebar/Sidebar.js.map +2 -2
  100. package/dist/components/layout/topbar/Topbar.js +1 -3
  101. package/dist/components/layout/topbar/Topbar.js.map +2 -2
  102. package/dist/hooks/createControllableStore.d.ts.map +1 -1
  103. package/dist/hooks/createControllableStore.js +8 -5
  104. package/dist/hooks/createControllableStore.js.map +1 -1
  105. package/dist/hooks/useLocalStorage.d.ts.map +1 -1
  106. package/dist/hooks/useLocalStorage.js +3 -2
  107. package/dist/hooks/useLocalStorage.js.map +1 -1
  108. package/dist/hooks/useSyncConfig.d.ts.map +1 -1
  109. package/dist/hooks/useSyncConfig.js +5 -4
  110. package/dist/hooks/useSyncConfig.js.map +1 -1
  111. package/dist/providers/i18n/locales/en.d.ts +2 -3
  112. package/dist/providers/i18n/locales/en.d.ts.map +1 -1
  113. package/dist/providers/i18n/locales/en.js +3 -4
  114. package/dist/providers/i18n/locales/en.js.map +1 -1
  115. package/dist/providers/i18n/locales/ko.d.ts +2 -3
  116. package/dist/providers/i18n/locales/ko.d.ts.map +1 -1
  117. package/dist/providers/i18n/locales/ko.js +3 -4
  118. package/dist/providers/i18n/locales/ko.js.map +1 -1
  119. package/dist/providers/shared-data/SharedDataProvider.d.ts.map +1 -1
  120. package/dist/providers/shared-data/SharedDataProvider.js +0 -1
  121. package/dist/providers/shared-data/SharedDataProvider.js.map +1 -1
  122. package/docs/display-feedback.md +279 -0
  123. package/docs/features.md +357 -213
  124. package/docs/form-controls.md +261 -403
  125. package/docs/layout-data.md +386 -0
  126. package/docs/providers-hooks.md +411 -0
  127. package/package.json +5 -5
  128. package/src/components/data/list/ListItem.styles.ts +14 -2
  129. package/src/components/data/list/ListItem.tsx +13 -4
  130. package/src/components/data/sheet/DataSheet.tsx +6 -10
  131. package/src/components/data/sheet/hooks/createDataSheetExpansion.ts +17 -18
  132. package/src/components/data/sheet/hooks/createDataSheetReorder.ts +12 -13
  133. package/src/components/data/sheet/hooks/createDataSheetSelection.ts +9 -3
  134. package/src/components/disclosure/Dialog.tsx +45 -59
  135. package/src/components/disclosure/Dropdown.tsx +4 -14
  136. package/src/components/disclosure/Tabs.tsx +12 -17
  137. package/src/components/features/crud-detail/CrudDetail.tsx +4 -4
  138. package/src/components/features/crud-sheet/CrudSheet.tsx +12 -5
  139. package/src/components/features/data-select-button/DataSelectButton.tsx +39 -32
  140. package/src/components/features/permission-table/PermissionTable.tsx +1 -1
  141. package/src/components/feedback/busy/BusyContainer.tsx +12 -18
  142. package/src/components/form-control/DropdownTrigger.styles.ts +1 -1
  143. package/src/components/form-control/checkbox/SelectableBase.tsx +10 -16
  144. package/src/components/form-control/combobox/Combobox.tsx +42 -16
  145. package/src/components/form-control/date-range-picker/DateRangePicker.tsx +7 -8
  146. package/src/components/form-control/editor/RichTextEditor.tsx +14 -16
  147. package/src/components/form-control/field/DatePicker.tsx +3 -2
  148. package/src/components/form-control/field/DateTimePicker.tsx +3 -2
  149. package/src/components/form-control/field/Field.styles.ts +6 -8
  150. package/src/components/form-control/field/NumberInput.tsx +9 -10
  151. package/src/components/form-control/field/TextInput.tsx +3 -2
  152. package/src/components/form-control/field/Textarea.tsx +14 -12
  153. package/src/components/form-control/field/TimePicker.tsx +3 -2
  154. package/src/components/form-control/numpad/Numpad.tsx +16 -18
  155. package/src/components/form-control/select/Select.tsx +41 -13
  156. package/src/components/form-control/state-preset/StatePreset.tsx +39 -71
  157. package/src/components/layout/FormGroup.tsx +1 -1
  158. package/src/components/layout/FormTable.tsx +3 -3
  159. package/src/components/layout/sidebar/Sidebar.tsx +2 -3
  160. package/src/components/layout/topbar/Topbar.tsx +2 -2
  161. package/src/hooks/createControllableStore.ts +8 -4
  162. package/src/hooks/useLocalStorage.ts +3 -2
  163. package/src/hooks/useSyncConfig.ts +5 -4
  164. package/src/providers/i18n/locales/en.ts +2 -3
  165. package/src/providers/i18n/locales/ko.ts +2 -3
  166. package/src/providers/shared-data/SharedDataProvider.tsx +0 -1
  167. package/tests/components/features/crud-detail/CrudDetail.spec.tsx +49 -0
  168. package/tests/components/features/data-select-button/DataSelectButton.spec.tsx +62 -7
  169. package/tests/components/form-control/combobox/Combobox.spec.tsx +3 -3
  170. package/tests/components/form-control/date-range-picker/DateRangePicker.spec.tsx +56 -0
  171. package/tests/components/form-control/select/SelectItem.spec.tsx +5 -0
  172. package/tests/providers/shared-data/SharedDataProvider.spec.tsx +0 -104
  173. package/docs/data.md +0 -204
  174. package/docs/disclosure.md +0 -146
  175. package/docs/display.md +0 -125
  176. package/docs/feedback.md +0 -156
  177. package/docs/helpers.md +0 -173
  178. package/docs/hooks.md +0 -146
  179. package/docs/layout.md +0 -94
  180. package/docs/providers.md +0 -180
@@ -137,7 +137,9 @@ const ComboboxItem: ParentComponent<ComboboxItemProps> = <TValue,>(
137
137
  //#endregion
138
138
 
139
139
  // Props definition
140
- export interface ComboboxProps<TValue = unknown> {
140
+
141
+ /** Base props shared by all Combobox variants */
142
+ interface ComboboxBaseProps<TValue> {
141
143
  /** Currently selected value */
142
144
  value?: TValue;
143
145
 
@@ -150,12 +152,6 @@ export interface ComboboxProps<TValue = unknown> {
150
152
  /** Debounce delay (default: 300ms) */
151
153
  debounceMs?: number;
152
154
 
153
- /** Allow custom values */
154
- allowsCustomValue?: boolean;
155
-
156
- /** Custom value parsing function */
157
- parseCustomValue?: (text: string) => TValue;
158
-
159
155
  /** Function to render selected value (required) */
160
156
  renderValue: (value: TValue) => JSX.Element;
161
157
 
@@ -190,6 +186,29 @@ export interface ComboboxProps<TValue = unknown> {
190
186
  children?: JSX.Element;
191
187
  }
192
188
 
189
+ /** Custom value with parser: TValue can be anything */
190
+ interface ComboboxCustomParserProps<TValue> extends ComboboxBaseProps<TValue> {
191
+ allowsCustomValue: true;
192
+ parseCustomValue: (text: string) => TValue;
193
+ }
194
+
195
+ /** Custom value without parser: TValue MUST be string */
196
+ interface ComboboxCustomStringProps extends ComboboxBaseProps<string> {
197
+ allowsCustomValue: true;
198
+ parseCustomValue?: undefined;
199
+ }
200
+
201
+ /** No custom value (default) */
202
+ interface ComboboxDefaultProps<TValue> extends ComboboxBaseProps<TValue> {
203
+ allowsCustomValue?: false;
204
+ parseCustomValue?: undefined;
205
+ }
206
+
207
+ export type ComboboxProps<TValue = unknown> =
208
+ | ComboboxCustomParserProps<TValue>
209
+ | ComboboxCustomStringProps
210
+ | ComboboxDefaultProps<TValue>;
211
+
193
212
  /**
194
213
  * Combobox component
195
214
  *
@@ -220,8 +239,15 @@ export interface ComboboxProps<TValue = unknown> {
220
239
  * </Combobox>
221
240
  * ```
222
241
  */
242
+ /** Internal props used after splitProps — collapses the discriminated union for runtime use */
243
+ interface ComboboxInternalProps<TValue> extends ComboboxBaseProps<TValue> {
244
+ allowsCustomValue?: boolean;
245
+ parseCustomValue?: (text: string) => TValue;
246
+ children?: JSX.Element;
247
+ }
248
+
223
249
  const ComboboxInner = <TValue,>(props: ComboboxProps<TValue>) => {
224
- const [local, rest] = splitProps(props as ComboboxProps<TValue> & { children?: JSX.Element }, [
250
+ const [local, rest] = splitProps(props as ComboboxInternalProps<TValue>, [
225
251
  "children",
226
252
  "class",
227
253
  "style",
@@ -252,8 +278,8 @@ const ComboboxInner = <TValue,>(props: ComboboxProps<TValue>) => {
252
278
  // Selected value management (controlled/uncontrolled pattern)
253
279
  const [getValue, setInternalValue] = createControllableSignal<TValue | undefined>({
254
280
  value: () => local.value,
255
- onChange: () => local.onValueChange,
256
- } as Parameters<typeof createControllableSignal<TValue | undefined>>[0]);
281
+ onChange: () => local.onValueChange as ((value: TValue | undefined) => void) | undefined,
282
+ });
257
283
 
258
284
  // Debounce queue (created once on mount, debounceMs only used as initial value)
259
285
  const debounceQueue = new DebounceQueue(local.debounceMs ?? 300);
@@ -270,7 +296,7 @@ const ComboboxInner = <TValue,>(props: ComboboxProps<TValue>) => {
270
296
 
271
297
  // Select value
272
298
  const selectValue = (value: TValue) => {
273
- setInternalValue(value as any);
299
+ setInternalValue(value);
274
300
  setQuery("");
275
301
  setOpen(false);
276
302
  };
@@ -346,9 +372,8 @@ const ComboboxInner = <TValue,>(props: ComboboxProps<TValue>) => {
346
372
  if (local.parseCustomValue) {
347
373
  selectValue(local.parseCustomValue(query()));
348
374
  } else {
349
- setInternalValue(undefined as any);
350
- setQuery("");
351
- setOpen(false);
375
+ // TValue is string when parseCustomValue is not provided (enforced by type system)
376
+ selectValue(query() as TValue);
352
377
  }
353
378
  }
354
379
  };
@@ -391,6 +416,7 @@ const ComboboxInner = <TValue,>(props: ComboboxProps<TValue>) => {
391
416
  class={clsx("min-w-0 flex-1 bg-transparent outline-none", text.placeholder)}
392
417
  value={query()}
393
418
  placeholder={currentValue === undefined ? local.placeholder : undefined}
419
+
394
420
  disabled={local.disabled}
395
421
  autocomplete="one-time-code"
396
422
  onInput={handleInput}
@@ -399,7 +425,7 @@ const ComboboxInner = <TValue,>(props: ComboboxProps<TValue>) => {
399
425
  }
400
426
 
401
427
  // Show value if selected and dropdown is closed
402
- return <div class="truncate">{local.renderValue(currentValue)}</div>;
428
+ return <div class="whitespace-nowrap">{local.renderValue(currentValue)}</div>;
403
429
  };
404
430
 
405
431
  // Render items
@@ -454,7 +480,7 @@ const ComboboxInner = <TValue,>(props: ComboboxProps<TValue>) => {
454
480
  style={local.style}
455
481
  onKeyDown={handleTriggerKeyDown}
456
482
  >
457
- <div class="flex-1 overflow-hidden whitespace-nowrap">{renderDisplayContent()}</div>
483
+ <div class="flex-1 whitespace-nowrap">{renderDisplayContent()}</div>
458
484
  <div class={chevronWrapperClass}>
459
485
  <Show
460
486
  when={busyCount() > 0}
@@ -3,9 +3,8 @@ import clsx from "clsx";
3
3
  import { twMerge } from "tailwind-merge";
4
4
  import { DateOnly } from "@simplysm/core-common";
5
5
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
6
- import { type FieldSize } from "../field/Field.styles";
7
6
  import { text } from "../../../styles/base.styles";
8
- import { gap } from "../../../styles/control.styles";
7
+ import { type ComponentSize, gap } from "../../../styles/control.styles";
9
8
  import { DatePicker } from "../field/DatePicker";
10
9
  import { Select } from "../select/Select";
11
10
  import { useI18n } from "../../../providers/i18n/I18nProvider";
@@ -38,7 +37,7 @@ export interface DateRangePickerProps {
38
37
  disabled?: boolean;
39
38
 
40
39
  /** Size */
41
- size?: FieldSize;
40
+ size?: ComponentSize;
42
41
 
43
42
  /** Custom class */
44
43
  class?: string;
@@ -153,11 +152,8 @@ export const DateRangePicker: Component<DateRangePickerProps> = (props) => {
153
152
  setTo(newTo);
154
153
  };
155
154
 
156
- // Wrapper CSS class
157
- const getWrapperClass = () => twMerge(clsx("inline-flex items-center", gap.md), local.class);
158
-
159
155
  return (
160
- <div {...rest} data-date-range-picker class={getWrapperClass()} style={local.style}>
156
+ <div {...rest} data-date-range-picker class={twMerge(clsx("inline-flex items-center", gap.md), local.class)} style={local.style}>
161
157
  <Select
162
158
  value={periodType()}
163
159
  onValueChange={handlePeriodTypeChange}
@@ -172,7 +168,7 @@ export const DateRangePicker: Component<DateRangePickerProps> = (props) => {
172
168
  required
173
169
  disabled={local.disabled}
174
170
  size={local.size}
175
- inset
171
+ class="min-w-0"
176
172
  >
177
173
  <Select.Item value={"day" as DateRangePeriodType}>
178
174
  {i18n.t("dateRangePicker.day")}
@@ -192,6 +188,7 @@ export const DateRangePicker: Component<DateRangePickerProps> = (props) => {
192
188
  unit={periodType() === "month" ? "month" : "date"}
193
189
  value={from()}
194
190
  onValueChange={handleFromChange}
191
+ required={local.required}
195
192
  disabled={local.disabled}
196
193
  size={local.size}
197
194
  />
@@ -201,6 +198,7 @@ export const DateRangePicker: Component<DateRangePickerProps> = (props) => {
201
198
  unit="date"
202
199
  value={from()}
203
200
  onValueChange={handleFromChange}
201
+ required={local.required}
204
202
  disabled={local.disabled}
205
203
  size={local.size}
206
204
  />
@@ -210,6 +208,7 @@ export const DateRangePicker: Component<DateRangePickerProps> = (props) => {
210
208
  value={to()}
211
209
  onValueChange={handleToChange}
212
210
  min={from()}
211
+ required={local.required}
213
212
  disabled={local.disabled}
214
213
  size={local.size}
215
214
  />
@@ -23,9 +23,8 @@ import TableHeader from "@tiptap/extension-table-header";
23
23
  import TableCell from "@tiptap/extension-table-cell";
24
24
  import Image from "@tiptap/extension-image";
25
25
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
26
- import type { FieldSize } from "../field/Field.styles";
27
26
  import { bg, border, text } from "../../../styles/base.styles";
28
- import { pad } from "../../../styles/control.styles";
27
+ import { type ComponentSize, pad } from "../../../styles/control.styles";
29
28
  import { EditorToolbar } from "./EditorToolbar";
30
29
 
31
30
  export interface RichTextEditorProps {
@@ -39,7 +38,7 @@ export interface RichTextEditorProps {
39
38
  disabled?: boolean;
40
39
 
41
40
  /** Size */
42
- size?: FieldSize;
41
+ size?: ComponentSize;
43
42
 
44
43
  /** Custom class */
45
44
  class?: string;
@@ -49,7 +48,7 @@ export interface RichTextEditorProps {
49
48
  }
50
49
 
51
50
  // Editor content size-based style
52
- const editorContentSizeClasses: Record<FieldSize, string> = {
51
+ const editorContentSizeClasses: Record<ComponentSize, string> = {
53
52
  md: clsx(pad.xl, "min-h-32"),
54
53
  xs: clsx(pad.xs, "min-h-12"),
55
54
  sm: clsx(pad.sm, "min-h-24"),
@@ -146,18 +145,17 @@ export const RichTextEditor: Component<RichTextEditorProps> = (props) => {
146
145
  editor()?.destroy();
147
146
  });
148
147
 
149
- const getWrapperClass = () =>
150
- twMerge(
151
- clsx("flex flex-col bg-primary-50 dark:bg-primary-950/30", text.default, "border", border.default, "rounded focus-within:border-primary-500"),
152
- local.disabled && clsx(bg.muted, text.muted),
153
- local.class,
154
- );
155
-
156
- const getContentClass = () =>
157
- twMerge("outline-none prose prose-sm max-w-none dark:prose-invert", editorContentSizeClasses[local.size ?? "md"]);
158
-
159
148
  return (
160
- <div {...rest} data-rich-text-editor class={getWrapperClass()} style={local.style}>
149
+ <div
150
+ {...rest}
151
+ data-rich-text-editor
152
+ class={twMerge(
153
+ clsx("flex flex-col", text.default, "border", border.default, "rounded focus-within:border-primary-500"),
154
+ local.disabled && clsx(bg.muted, text.muted),
155
+ local.class,
156
+ )}
157
+ style={local.style}
158
+ >
161
159
  <Show when={editor()}>
162
160
  {(instance) => (
163
161
  <Show when={!local.disabled}>
@@ -165,7 +163,7 @@ export const RichTextEditor: Component<RichTextEditorProps> = (props) => {
165
163
  </Show>
166
164
  )}
167
165
  </Show>
168
- <div ref={editorRef} class={getContentClass()} />
166
+ <div ref={editorRef} class={twMerge("outline-none prose prose-sm max-w-none dark:prose-invert bg-primary-50 dark:bg-primary-950/30", editorContentSizeClasses[local.size ?? "md"])} />
169
167
  </div>
170
168
  );
171
169
  };
@@ -1,7 +1,8 @@
1
1
  import { type Component, createMemo, type JSX, splitProps } from "solid-js";
2
2
  import { DateOnly } from "@simplysm/core-common";
3
3
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
4
- import { fieldInputClass, type FieldSize, getFieldWrapperClass } from "./Field.styles";
4
+ import { fieldInputClass, getFieldWrapperClass } from "./Field.styles";
5
+ import type { ComponentSize } from "../../../styles/control.styles";
5
6
  import { useI18n } from "../../../providers/i18n/I18nProvider";
6
7
  import { FieldShell } from "./FieldShell";
7
8
 
@@ -33,7 +34,7 @@ export interface DatePickerProps {
33
34
  readOnly?: boolean;
34
35
 
35
36
  /** Size */
36
- size?: FieldSize;
37
+ size?: ComponentSize;
37
38
 
38
39
  /** Borderless style */
39
40
  inset?: boolean;
@@ -1,7 +1,8 @@
1
1
  import { type Component, createMemo, type JSX, splitProps } from "solid-js";
2
2
  import { DateTime } from "@simplysm/core-common";
3
3
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
4
- import { type FieldSize, fieldInputClass, getFieldWrapperClass } from "./Field.styles";
4
+ import { fieldInputClass, getFieldWrapperClass } from "./Field.styles";
5
+ import type { ComponentSize } from "../../../styles/control.styles";
5
6
  import { useI18n } from "../../../providers/i18n/I18nProvider";
6
7
  import { FieldShell } from "./FieldShell";
7
8
 
@@ -33,7 +34,7 @@ export interface DateTimePickerProps {
33
34
  readOnly?: boolean;
34
35
 
35
36
  /** Size */
36
- size?: FieldSize;
37
+ size?: ComponentSize;
37
38
 
38
39
  /** Borderless style */
39
40
  inset?: boolean;
@@ -3,8 +3,6 @@ import { twMerge } from "tailwind-merge";
3
3
  import { type ComponentSize, gap, pad } from "../../../styles/control.styles";
4
4
  import { border, text } from "../../../styles/base.styles";
5
5
 
6
- export type FieldSize = ComponentSize;
7
-
8
6
  // ── Form Field Common Surface (background + text + border + focus) ──
9
7
  export const fieldSurface = clsx(
10
8
  "bg-primary-50 dark:bg-primary-950/30",
@@ -23,7 +21,7 @@ export const fieldBaseClass = clsx(
23
21
  );
24
22
 
25
23
  // Size-specific styles
26
- export const fieldSizeClasses: Record<FieldSize, string> = {
24
+ export const fieldSizeClasses: Record<ComponentSize, string> = {
27
25
  md: clsx("h-field", pad.md),
28
26
  xs: clsx("h-field-xs", pad.xs),
29
27
  sm: clsx("h-field-sm", pad.sm),
@@ -41,7 +39,7 @@ export const fieldInsetClass = clsx(
41
39
  );
42
40
 
43
41
  // Inset heights (excluding 2px border)
44
- export const fieldInsetSizeHeightClasses: Record<FieldSize, string> = {
42
+ export const fieldInsetSizeHeightClasses: Record<ComponentSize, string> = {
45
43
  md: clsx`h-field-inset`,
46
44
  xs: clsx`h-field-inset-xs`,
47
45
  sm: clsx`h-field-inset-sm`,
@@ -56,7 +54,7 @@ export const fieldDisabledClass = clsx("bg-base-100 text-base-500 dark:bg-base-8
56
54
  export const textAreaBaseClass = clsx("inline-block w-48", fieldSurface);
57
55
 
58
56
  // Textarea size-specific styles (h-field-* removed)
59
- export const textAreaSizeClasses: Record<FieldSize, string> = {
57
+ export const textAreaSizeClasses: Record<ComponentSize, string> = {
60
58
  md: pad.md,
61
59
  xs: pad.xs,
62
60
  sm: pad.sm,
@@ -74,7 +72,7 @@ export const fieldInputClass = clsx(
74
72
  );
75
73
 
76
74
  // Prefix icon gap classes (replaces nested ternary)
77
- export const fieldGapClasses: Record<FieldSize, string> = {
75
+ export const fieldGapClasses: Record<ComponentSize, string> = {
78
76
  md: gap.md,
79
77
  xs: gap.xs,
80
78
  sm: gap.sm,
@@ -84,7 +82,7 @@ export const fieldGapClasses: Record<FieldSize, string> = {
84
82
 
85
83
  // Shared wrapper class generation function
86
84
  export function getFieldWrapperClass(options: {
87
- size?: FieldSize;
85
+ size?: ComponentSize;
88
86
  disabled?: boolean;
89
87
  inset?: boolean;
90
88
  includeCustomClass?: string | false;
@@ -103,7 +101,7 @@ export function getFieldWrapperClass(options: {
103
101
 
104
102
  // Textarea-specific wrapper class generation function
105
103
  export function getTextareaWrapperClass(options: {
106
- size?: FieldSize;
104
+ size?: ComponentSize;
107
105
  disabled?: boolean;
108
106
  inset?: boolean;
109
107
  includeCustomClass?: string | false;
@@ -9,23 +9,16 @@ import {
9
9
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
10
10
  import { createSlot } from "../../../helpers/createSlot";
11
11
  import {
12
- type FieldSize,
13
12
  fieldInputClass,
14
13
  fieldGapClasses,
15
14
  getFieldWrapperClass,
16
15
  } from "./Field.styles";
16
+ import type { ComponentSize } from "../../../styles/control.styles";
17
17
  import { PlaceholderFallback } from "./FieldPlaceholder";
18
18
  import { useI18n } from "../../../providers/i18n/I18nProvider";
19
19
  import { FieldShell } from "./FieldShell";
20
20
  import clsx from "clsx";
21
21
 
22
- // NumberInput-specific input style (right-aligned + spinner hidden)
23
- const numberInputClass = clsx(
24
- fieldInputClass,
25
- "text-right",
26
- "[&::-webkit-outer-spin-button]:appearance-none",
27
- "[&::-webkit-inner-spin-button]:appearance-none",
28
- );
29
22
 
30
23
  const [NumberInputPrefixSlot, createNumberInputPrefixAccessor] = createSlot<{ children: JSX.Element }>();
31
24
  export const NumberInputPrefix = NumberInputPrefixSlot;
@@ -56,7 +49,7 @@ export interface NumberInputProps {
56
49
  readOnly?: boolean;
57
50
 
58
51
  /** Size */
59
- size?: FieldSize;
52
+ size?: ComponentSize;
60
53
 
61
54
  /** Borderless style */
62
55
  inset?: boolean;
@@ -331,9 +324,15 @@ const NumberInputInner = (props: NumberInputProps): JSX.Element => {
331
324
  <input
332
325
  type="text"
333
326
  inputmode="numeric"
334
- class={numberInputClass}
327
+ class={clsx(
328
+ fieldInputClass,
329
+ "text-right",
330
+ "[&::-webkit-outer-spin-button]:appearance-none",
331
+ "[&::-webkit-inner-spin-button]:appearance-none",
332
+ )}
335
333
  value={displayValue()}
336
334
  placeholder={local.placeholder}
335
+
337
336
  title={local.title}
338
337
  autocomplete="one-time-code"
339
338
  onInput={handleInput}
@@ -5,9 +5,9 @@ import { createIMEHandler } from "../../../hooks/createIMEHandler";
5
5
  import {
6
6
  fieldGapClasses,
7
7
  fieldInputClass,
8
- type FieldSize,
9
8
  getFieldWrapperClass,
10
9
  } from "./Field.styles";
10
+ import type { ComponentSize } from "../../../styles/control.styles";
11
11
  import { PlaceholderFallback } from "./FieldPlaceholder";
12
12
  import { FieldShell } from "./FieldShell";
13
13
  import { useI18n } from "../../../providers/i18n/I18nProvider";
@@ -41,7 +41,7 @@ export interface TextInputProps {
41
41
  readOnly?: boolean;
42
42
 
43
43
  /** Size */
44
- size?: FieldSize;
44
+ size?: ComponentSize;
45
45
 
46
46
  /** Borderless style */
47
47
  inset?: boolean;
@@ -286,6 +286,7 @@ const TextInputInner = (props: TextInputProps) => {
286
286
  class={fieldInputClass}
287
287
  value={inputValue()}
288
288
  placeholder={local.placeholder}
289
+
289
290
  title={local.title}
290
291
  autocomplete={local.autocomplete ?? "one-time-code"}
291
292
  onInput={handleInput}
@@ -4,7 +4,8 @@ import { twMerge } from "tailwind-merge";
4
4
  import { text } from "../../../styles/base.styles";
5
5
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
6
6
  import { createIMEHandler } from "../../../hooks/createIMEHandler";
7
- import { type FieldSize, textAreaSizeClasses, getTextareaWrapperClass } from "./Field.styles";
7
+ import { textAreaSizeClasses, getTextareaWrapperClass } from "./Field.styles";
8
+ import type { ComponentSize } from "../../../styles/control.styles";
8
9
  import { PlaceholderFallback } from "./FieldPlaceholder";
9
10
  import { FieldShell } from "./FieldShell";
10
11
  import { useI18n } from "../../../providers/i18n/I18nProvider";
@@ -29,7 +30,7 @@ export interface TextareaProps {
29
30
  readOnly?: boolean;
30
31
 
31
32
  /** Size */
32
- size?: FieldSize;
33
+ size?: ComponentSize;
33
34
 
34
35
  /** Borderless style */
35
36
  inset?: boolean;
@@ -59,13 +60,6 @@ export interface TextareaProps {
59
60
  style?: JSX.CSSProperties;
60
61
  }
61
62
 
62
- const textareaBaseClass = clsx(
63
- "absolute left-0 top-0",
64
- "size-full",
65
- "resize-none overflow-hidden",
66
- "bg-transparent",
67
- text.placeholder,
68
- );
69
63
 
70
64
  /**
71
65
  * Textarea component
@@ -164,8 +158,6 @@ export const Textarea: Component<TextareaProps> = (props) => {
164
158
  "whitespace-pre-wrap break-all",
165
159
  );
166
160
 
167
- const getTextareaClass = () =>
168
- twMerge(textareaBaseClass, textAreaSizeClasses[local.size ?? "md"], local.inset && "p-0");
169
161
 
170
162
  // Whether editable
171
163
  const isEditable = () => !local.disabled && !local.readOnly;
@@ -228,7 +220,17 @@ export const Textarea: Component<TextareaProps> = (props) => {
228
220
  {contentForHeight()}
229
221
  </div>
230
222
  <textarea
231
- class={getTextareaClass()}
223
+ class={twMerge(
224
+ clsx(
225
+ "absolute left-0 top-0",
226
+ "size-full",
227
+ "resize-none overflow-hidden",
228
+ "bg-transparent",
229
+ text.placeholder,
230
+ ),
231
+ textAreaSizeClasses[local.size ?? "md"],
232
+ local.inset && "p-0",
233
+ )}
232
234
  value={value()}
233
235
  placeholder={local.placeholder}
234
236
  title={local.title}
@@ -1,7 +1,8 @@
1
1
  import { type Component, createMemo, type JSX, splitProps } from "solid-js";
2
2
  import { Time } from "@simplysm/core-common";
3
3
  import { createControllableSignal } from "../../../hooks/createControllableSignal";
4
- import { type FieldSize, fieldInputClass, getFieldWrapperClass } from "./Field.styles";
4
+ import { fieldInputClass, getFieldWrapperClass } from "./Field.styles";
5
+ import type { ComponentSize } from "../../../styles/control.styles";
5
6
  import { useI18n } from "../../../providers/i18n/I18nProvider";
6
7
  import { FieldShell } from "./FieldShell";
7
8
 
@@ -27,7 +28,7 @@ export interface TimePickerProps {
27
28
  readOnly?: boolean;
28
29
 
29
30
  /** Size */
30
- size?: FieldSize;
31
+ size?: ComponentSize;
31
32
 
32
33
  /** Borderless style */
33
34
  inset?: boolean;
@@ -127,7 +127,7 @@ export const Numpad: Component<NumpadProps> = (props) => {
127
127
  setInputStr(valueToInputStr(val));
128
128
  };
129
129
 
130
- const buttonSize = () => props.size ?? "lg";
130
+ const buttonSize = () => props.size ?? "md";
131
131
 
132
132
  return (
133
133
  <div data-numpad class={twMerge(clsx("grid grid-cols-3", gap.sm, "w-auto"), props.class)} style={props.style}>
@@ -138,7 +138,7 @@ export const Numpad: Component<NumpadProps> = (props) => {
138
138
  onValueChange={handleFieldValueChange}
139
139
  placeholder={props.placeholder}
140
140
  readOnly={props.inputDisabled}
141
- inset
141
+ size={buttonSize()}
142
142
  class="w-full"
143
143
  useGrouping={false}
144
144
  />
@@ -148,7 +148,6 @@ export const Numpad: Component<NumpadProps> = (props) => {
148
148
  theme="primary"
149
149
  variant="solid"
150
150
  size={buttonSize()}
151
- inset
152
151
  disabled={props.required && value() == null}
153
152
  onClick={handleEnter}
154
153
  >
@@ -158,60 +157,59 @@ export const Numpad: Component<NumpadProps> = (props) => {
158
157
 
159
158
  {/* Row 2: optional Minus + C + BS */}
160
159
  <Show when={props.withMinusButton}>
161
- <Button size={buttonSize()} inset onClick={handleMinus}>
160
+ <Button size={buttonSize()} onClick={handleMinus}>
162
161
  -
163
162
  </Button>
164
163
  </Show>
165
164
  <Button
166
165
  size={buttonSize()}
167
- inset
168
- onClick={handleClear}
166
+ onClick={handleClear}
169
167
  class={clsx(props.withMinusButton ? "col-span-1" : "col-span-2", "text-danger-500")}
170
168
  >
171
169
  <Icon icon={IconEraser} />
172
170
  </Button>
173
- <Button size={buttonSize()} inset onClick={handleBackspace} class="text-warning-500">
171
+ <Button size={buttonSize()} onClick={handleBackspace} class="text-warning-500">
174
172
  <Icon icon={IconArrowLeft} />
175
173
  </Button>
176
174
 
177
175
  {/* Row 3: 7 8 9 */}
178
- <Button size={buttonSize()} inset onClick={() => handleDigit("7")}>
176
+ <Button size={buttonSize()} onClick={() => handleDigit("7")}>
179
177
  7
180
178
  </Button>
181
- <Button size={buttonSize()} inset onClick={() => handleDigit("8")}>
179
+ <Button size={buttonSize()} onClick={() => handleDigit("8")}>
182
180
  8
183
181
  </Button>
184
- <Button size={buttonSize()} inset onClick={() => handleDigit("9")}>
182
+ <Button size={buttonSize()} onClick={() => handleDigit("9")}>
185
183
  9
186
184
  </Button>
187
185
 
188
186
  {/* Row 4: 4 5 6 */}
189
- <Button size={buttonSize()} inset onClick={() => handleDigit("4")}>
187
+ <Button size={buttonSize()} onClick={() => handleDigit("4")}>
190
188
  4
191
189
  </Button>
192
- <Button size={buttonSize()} inset onClick={() => handleDigit("5")}>
190
+ <Button size={buttonSize()} onClick={() => handleDigit("5")}>
193
191
  5
194
192
  </Button>
195
- <Button size={buttonSize()} inset onClick={() => handleDigit("6")}>
193
+ <Button size={buttonSize()} onClick={() => handleDigit("6")}>
196
194
  6
197
195
  </Button>
198
196
 
199
197
  {/* Row 5: 1 2 3 */}
200
- <Button size={buttonSize()} inset onClick={() => handleDigit("1")}>
198
+ <Button size={buttonSize()} onClick={() => handleDigit("1")}>
201
199
  1
202
200
  </Button>
203
- <Button size={buttonSize()} inset onClick={() => handleDigit("2")}>
201
+ <Button size={buttonSize()} onClick={() => handleDigit("2")}>
204
202
  2
205
203
  </Button>
206
- <Button size={buttonSize()} inset onClick={() => handleDigit("3")}>
204
+ <Button size={buttonSize()} onClick={() => handleDigit("3")}>
207
205
  3
208
206
  </Button>
209
207
 
210
208
  {/* Row 6: 0 (colspan 2) + . */}
211
- <Button size={buttonSize()} inset class="col-span-2" onClick={() => handleDigit("0")}>
209
+ <Button size={buttonSize()} class="col-span-2" onClick={() => handleDigit("0")}>
212
210
  0
213
211
  </Button>
214
- <Button size={buttonSize()} inset onClick={handleDot}>
212
+ <Button size={buttonSize()} onClick={handleDot}>
215
213
  .
216
214
  </Button>
217
215
  </div>