Ver código fonte

[stdf]新增 Form 组件

dufu1991 10 meses atrás
pai
commit
19ce815295
82 arquivos alterados com 1686 adições e 100 exclusões
  1. 0 0
      docs/mds/components/form/FAQ.md
  2. 0 0
      docs/mds/components/form/FAQ_en.md
  3. 171 0
      docs/mds/components/form/api.md
  4. 171 0
      docs/mds/components/form/api_en.md
  5. 49 0
      docs/mds/components/form/guide.md
  6. 47 0
      docs/mds/components/form/guide_en.md
  7. 0 0
      docs/mds/components/form/version.md
  8. 0 0
      docs/mds/components/form/version_en.md
  9. 13 2
      packages/stdf/src/data/menuList.ts
  10. 462 0
      packages/stdf/src/lib/components/form/Form.svelte
  11. 66 29
      packages/stdf/src/lib/components/picker/Picker.svelte
  12. 1 0
      packages/stdf/src/lib/index.ts
  13. 5 1
      packages/stdf/src/lib/lang/ar_EG.ts
  14. 5 1
      packages/stdf/src/lib/lang/az_AZ.ts
  15. 5 1
      packages/stdf/src/lib/lang/bg_BG.ts
  16. 5 1
      packages/stdf/src/lib/lang/bn_BD.ts
  17. 5 1
      packages/stdf/src/lib/lang/ca_ES.ts
  18. 5 1
      packages/stdf/src/lib/lang/cs_CZ.ts
  19. 5 1
      packages/stdf/src/lib/lang/da_DK.ts
  20. 5 1
      packages/stdf/src/lib/lang/de_DE.ts
  21. 5 1
      packages/stdf/src/lib/lang/el_GR.ts
  22. 5 1
      packages/stdf/src/lib/lang/en_GB.ts
  23. 5 1
      packages/stdf/src/lib/lang/en_US.ts
  24. 5 1
      packages/stdf/src/lib/lang/es_ES.ts
  25. 5 1
      packages/stdf/src/lib/lang/et_EE.ts
  26. 5 1
      packages/stdf/src/lib/lang/eu_ES.ts
  27. 5 1
      packages/stdf/src/lib/lang/fa_IR.ts
  28. 5 1
      packages/stdf/src/lib/lang/fi_FI.ts
  29. 5 1
      packages/stdf/src/lib/lang/fr_BE.ts
  30. 5 1
      packages/stdf/src/lib/lang/fr_CA.ts
  31. 5 1
      packages/stdf/src/lib/lang/fr_FR.ts
  32. 5 1
      packages/stdf/src/lib/lang/ga_IE.ts
  33. 5 1
      packages/stdf/src/lib/lang/gl_ES.ts
  34. 5 1
      packages/stdf/src/lib/lang/he_IL.ts
  35. 5 1
      packages/stdf/src/lib/lang/hi_IN.ts
  36. 5 1
      packages/stdf/src/lib/lang/hr_HR.ts
  37. 5 1
      packages/stdf/src/lib/lang/hu_HU.ts
  38. 5 1
      packages/stdf/src/lib/lang/hy_AM.ts
  39. 5 1
      packages/stdf/src/lib/lang/id_ID.ts
  40. 4 0
      packages/stdf/src/lib/lang/index.ts
  41. 5 1
      packages/stdf/src/lib/lang/is_IS.ts
  42. 5 1
      packages/stdf/src/lib/lang/it_IT.ts
  43. 5 1
      packages/stdf/src/lib/lang/ja_JP.ts
  44. 5 1
      packages/stdf/src/lib/lang/ka_GE.ts
  45. 5 1
      packages/stdf/src/lib/lang/kk_KZ.ts
  46. 5 1
      packages/stdf/src/lib/lang/km_KH.ts
  47. 5 1
      packages/stdf/src/lib/lang/kmr_IQ.ts
  48. 5 1
      packages/stdf/src/lib/lang/kn_IN.ts
  49. 5 1
      packages/stdf/src/lib/lang/ko_KR.ts
  50. 5 1
      packages/stdf/src/lib/lang/lt_LT.ts
  51. 5 1
      packages/stdf/src/lib/lang/lv_LV.ts
  52. 5 1
      packages/stdf/src/lib/lang/mk_MK.ts
  53. 5 1
      packages/stdf/src/lib/lang/ml_IN.ts
  54. 5 1
      packages/stdf/src/lib/lang/mn_MN.ts
  55. 5 1
      packages/stdf/src/lib/lang/ms_MY.ts
  56. 5 1
      packages/stdf/src/lib/lang/nb_NO.ts
  57. 5 1
      packages/stdf/src/lib/lang/ne_NP.ts
  58. 5 1
      packages/stdf/src/lib/lang/nl_BE.ts
  59. 5 1
      packages/stdf/src/lib/lang/nl_NL.ts
  60. 5 1
      packages/stdf/src/lib/lang/pl_PL.ts
  61. 5 1
      packages/stdf/src/lib/lang/pt_BR.ts
  62. 5 1
      packages/stdf/src/lib/lang/pt_PT.ts
  63. 5 1
      packages/stdf/src/lib/lang/ro_RO.ts
  64. 5 1
      packages/stdf/src/lib/lang/ru_RU.ts
  65. 5 1
      packages/stdf/src/lib/lang/si_LK.ts
  66. 5 1
      packages/stdf/src/lib/lang/sk_SK.ts
  67. 5 1
      packages/stdf/src/lib/lang/sl_SI.ts
  68. 5 1
      packages/stdf/src/lib/lang/sr_RS.ts
  69. 5 1
      packages/stdf/src/lib/lang/sv_SE.ts
  70. 5 1
      packages/stdf/src/lib/lang/ta_IN.ts
  71. 5 1
      packages/stdf/src/lib/lang/th_TH.ts
  72. 5 1
      packages/stdf/src/lib/lang/tk_TK.ts
  73. 5 1
      packages/stdf/src/lib/lang/tr_TR.ts
  74. 5 1
      packages/stdf/src/lib/lang/uk_UA.ts
  75. 5 1
      packages/stdf/src/lib/lang/ur_PK.ts
  76. 5 1
      packages/stdf/src/lib/lang/vi_VN.ts
  77. 5 1
      packages/stdf/src/lib/lang/zh_CN.ts
  78. 5 1
      packages/stdf/src/lib/lang/zh_HK.ts
  79. 5 1
      packages/stdf/src/lib/lang/zh_TW.ts
  80. 154 3
      packages/stdf/src/lib/types/index.ts
  81. 109 0
      packages/stdf/src/routes/form/en_US/+page.svelte
  82. 109 0
      packages/stdf/src/routes/form/zh_CN/+page.svelte

+ 0 - 0
docs/mds/components/form/FAQ.md


+ 0 - 0
docs/mds/components/form/FAQ_en.md


+ 171 - 0
docs/mds/components/form/api.md

@@ -0,0 +1,171 @@
+## Form Props
+
+| 名称           | 类型                                                                                     | 默认值    | 必传 | 说明                                      |
+| -------------- | ---------------------------------------------------------------------------------------- | --------- | ---- | ----------------------------------------- |
+| form           | `FormItemProps[]`                                                                        | -         | Y    | 表单配置项数组。                          |
+| submitText     | `string`                                                                                 | -         | N    | 提交按钮文字。                            |
+| submitButton   | [`ButtonProps`](https://stdf.design/components?nav=button&tab=1)                         | -         | N    | 提交按钮配置。                            |
+| resetText      | `string`\|`null`                                                                         | `null`    | N    | 重置按钮文字,传入 null 时不显示。       |
+| resetButton    | [`ButtonProps`](https://stdf.design/components?nav=button&tab=1)                         | -         | N    | 重置按钮配置。                            |
+| submitChildren | `Snippet`                                                                                | -         | N    | 自定义提交按钮内容。                     |
+| resetChildren  | `Snippet`                                                                                | -         | N    | 自定义重置按钮内容。                     |
+| space          | `'0'\|'1'\|'2'\|'4'\|'6'\|'8'`                                                           | `'0'`     | N    | 表单项垂直间距。                         |
+| card           | `boolean`                                                                                | `false`   | N    | 是否开启卡片布局。                       |
+| mx             | `'2'\|'3'\|'4'\|'6'\|'8'`                                                                | `'4'`     | N    | 水平外边距(card 模式时生效)。          |
+| px             | `'0'\|'1'\|'2'\|'4'\|'6'`                                                                | `'2'`     | N    | 水平内边距(card 模式时生效)。          |
+| radius         | `'sm'\|'md'\|'lg'\|'xl'\|'2xl'\|'3xl'\|'4xl'`                                            | `'xl'`    | N    | 卡片圆角(card 模式时生效)。            |
+| shadow         | `'none'\|'xs'\|'sm'\|'md'\|'lg'\|'xl'\|'2xl'`                                            | `'sm'`    | N    | 卡片阴影(card 模式时生效)。            |
+| onchange       | `(data: Record<string, FormValueProps>) => void`                                         | -         | N    | 表单项值变化时触发。                     |
+| onsubmit       | `(data: Record<string, FormValueProps>) => void`                                         | -         | N    | 提交时触发。                             |
+| onreset        | `() => void`                                                                             | -         | N    | 重置时触发。                             |
+
+## Form Events
+
+| 名称    | 类型                                                         | 参数                                        | 说明             |
+| ------- | ------------------------------------------------------------ | ------------------------------------------- | ---------------- |
+| onchange | `(data: Record<string, FormValueProps>) => void`             | data - 所有表单项的当前值                   | 表单项值变化时触发。 |
+| onsubmit | `(data: Record<string, FormValueProps>) => void`             | data - 所有表单项的当前值                   | 提交时触发。     |
+| onreset | `() => void`                                                 | -                                           | 重置时触发。     |
+
+## Form Snippets
+
+| 名称           | 类型                                                                | 参数 | 说明                   |
+| -------------- | ------------------------------------------------------------------- | ---- | ---------------------- |
+| submitChildren | [`Snippet`](https://svelte.dev/docs/svelte/snippet#Typing-snippets) | -    | 自定义提交按钮内容。   |
+| resetChildren  | [`Snippet`](https://svelte.dev/docs/svelte/snippet#Typing-snippets) | -    | 自定义重置按钮内容。   |
+
+## FormItemProps
+
+表单项通用配置:
+
+| 名称      | 类型                  | 说明                  |
+| --------- | --------------------- | --------------------- |
+| type      | `string`              | 表单项类型。          |
+| name      | `string`              | 表单项名称。          |
+| label     | `string`              | 表单项标题。          |
+| required  | `boolean`             | 是否必填。            |
+| initValue | `any`                 | 初始值。              |
+
+支持的表单项类型及配置:
+
+### input
+
+文本输入框。
+
+| 名称   | 类型     | 说明           |
+| ------ | -------- | -------------- |
+| type  | `'input'` | 类型标识。     |
+| input | `object` | Input 组件配置。|
+
+### numKeyboard
+
+数字键盘。
+
+| 名称       | 类型           | 说明                 |
+| ---------- | -------------- | -------------------- |
+| type      | `'numKeyboard'` | 类型标识。           |
+| numKeyboard | `object`       | NumKeyboard 组件配置。|
+| input     | `object`       | Input 组件配置。     |
+
+### timePicker
+
+时间选择器。
+
+| 名称       | 类型           | 说明                 |
+| ---------- | -------------- | -------------------- |
+| type      | `'timePicker'` | 类型标识。           |
+| timePicker | `object`       | TimePicker 组件配置。|
+| input     | `object`       | Input 组件配置。     |
+
+### actionSheet
+
+操作面板。
+
+| 名称       | 类型           | 说明                 |
+| ---------- | -------------- | -------------------- |
+| type      | `'actionSheet'` | 类型标识。           |
+| actionSheet | `object`       | ActionSheet 组件配置。|
+| input     | `object`       | Input 组件配置。     |
+
+### calendar
+
+日期选择器。
+
+| 名称     | 类型         | 说明             |
+| -------- | ------------ | ---------------- |
+| type    | `'calendar'` | 类型标识。       |
+| calendar | `object`     | Calendar 组件配置。|
+| input   | `object`     | Input 组件配置。 |
+
+### picker
+
+选择器。
+
+| 名称   | 类型     | 说明           |
+| ------ | -------- | -------------- |
+| type  | `'picker'` | 类型标识。     |
+| picker | `object` | Picker 组件配置。|
+| input | `object` | Input 组件配置。|
+
+### checkbox
+
+复选框组。
+
+| 名称     | 类型         | 说明             |
+| -------- | ------------ | ---------------- |
+| type    | `'checkbox'` | 类型标识。       |
+| checkbox | `object`     | Checkbox 组件配置。|
+
+### radio
+
+单选框组。
+
+| 名称  | 类型    | 说明       |
+| ----- | ------- | ---------- |
+| type | `'radio'` | 类型标识。 |
+| radio | `object` | Radio 组件配置。|
+
+### slider
+
+滑块。
+
+| 名称   | 类型     | 说明           |
+| ------ | -------- | -------------- |
+| type  | `'slider'` | 类型标识。     |
+| slider | `object` | Slider 组件配置。|
+
+### switch
+
+开关。
+
+| 名称   | 类型     | 说明           |
+| ------ | -------- | -------------- |
+| type  | `'switch'` | 类型标识。     |
+| switch | `object` | Switch 组件配置。|
+
+### stepper
+
+步进器。
+
+| 名称     | 类型         | 说明             |
+| -------- | ------------ | ---------------- |
+| type    | `'stepper'` | 类型标识。       |
+| stepper | `object`     | Stepper 组件配置。|
+
+## FormValueProps
+
+表单值类型为 `Record<string, FormValueProps>`,其中 FormValueProps 是所有表单项值的联合类型:
+
+| 表单项类型   | 值类型                           |
+| ------------ | -------------------------------- |
+| input        | `string`                         |
+| numKeyboard  | `string`                         |
+| timePicker   | `FormTimePickerValue`            |
+| actionSheet  | `FormActionSheetValue`           |
+| calendar     | `FormCalendarValue`              |
+| picker       | `FormPickerValue`                |
+| checkbox     | `string[]`                       |
+| radio        | `string`                         |
+| slider       | `FormSliderValue`                |
+| switch       | `boolean`                        |
+| stepper      | `number`                         |

+ 171 - 0
docs/mds/components/form/api_en.md

@@ -0,0 +1,171 @@
+## Form Props
+
+| Name           | Type                                                                                     | Default   | Required | Description                                      |
+| -------------- | ---------------------------------------------------------------------------------------- | --------- | -------- | ------------------------------------------------ |
+| form           | `FormItemProps[]`                                                                        | -         | Y        | Form configuration array.                        |
+| submitText     | `string`                                                                                 | -         | N        | Submit button text.                              |
+| submitButton   | [`ButtonProps`](https://stdf.design/components?nav=button&tab=1)                         | -         | N        | Submit button configuration.                     |
+| resetText      | `string`\|`null`                                                                         | `null`    | N        | Reset button text, pass null to hide.           |
+| resetButton    | [`ButtonProps`](https://stdf.design/components?nav=button&tab=1)                         | -         | N        | Reset button configuration.                      |
+| submitChildren | `Snippet`                                                                                | -         | N        | Custom submit button content.                    |
+| resetChildren  | `Snippet`                                                                                | -         | N        | Custom reset button content.                     |
+| space          | `'0'\|'1'\|'2'\|'4'\|'6'\|'8'`                                                           | `'0'`     | N        | Vertical spacing between form items.             |
+| card           | `boolean`                                                                                | `false`   | N        | Whether to enable card layout.                   |
+| mx             | `'2'\|'3'\|'4'\|'6'\|'8'`                                                                | `'4'`     | N        | Horizontal margin (works in card mode).          |
+| px             | `'0'\|'1'\|'2'\|'4'\|'6'`                                                                | `'2'`     | N        | Horizontal padding (works in card mode).         |
+| radius         | `'sm'\|'md'\|'lg'\|'xl'\|'2xl'\|'3xl'\|'4xl'`                                            | `'xl'`    | N        | Card border radius (works in card mode).         |
+| shadow         | `'none'\|'xs'\|'sm'\|'md'\|'lg'\|'xl'\|'2xl'`                                            | `'sm'`    | N        | Card shadow (works in card mode).                |
+| onchange       | `(data: Record<string, FormValueProps>) => void`                                         | -         | N        | Triggered when any form item value changes.      |
+| onsubmit       | `(data: Record<string, FormValueProps>) => void`                                         | -         | N        | Triggered when form is submitted.                |
+| onreset        | `() => void`                                                                             | -         | N        | Triggered when form is reset.                    |
+
+## Form Events
+
+| Name    | Type                                                         | Parameters                                  | Description                              |
+| ------- | ------------------------------------------------------------ | ------------------------------------------- | ---------------------------------------- |
+| onchange | `(data: Record<string, FormValueProps>) => void`             | data - current values of all form items     | Triggered when any form item value changes. |
+| onsubmit | `(data: Record<string, FormValueProps>) => void`             | data - current values of all form items     | Triggered when form is submitted.        |
+| onreset | `() => void`                                                 | -                                           | Triggered when form is reset.            |
+
+## Form Snippets
+
+| Name           | Type                                                                | Parameters | Description                    |
+| -------------- | ------------------------------------------------------------------- | ---------- | ------------------------------ |
+| submitChildren | [`Snippet`](https://svelte.dev/docs/svelte/snippet#Typing-snippets) | -          | Custom submit button content.  |
+| resetChildren  | [`Snippet`](https://svelte.dev/docs/svelte/snippet#Typing-snippets) | -          | Custom reset button content.   |
+
+## FormItemProps
+
+Common configuration for form items:
+
+| Name      | Type     | Description          |
+| --------- | -------- | -------------------- |
+| type      | `string` | Form item type.      |
+| name      | `string` | Form item name.      |
+| label     | `string` | Form item label.     |
+| required  | `boolean`| Whether required.    |
+| initValue | `any`    | Initial value.       |
+
+Supported form item types and configurations:
+
+### input
+
+Text input.
+
+| Name  | Type    | Description        |
+| ----- | ------- | ------------------ |
+| type | `'input'` | Type identifier.   |
+| input | `object` | Input component config.|
+
+### numKeyboard
+
+Number keyboard.
+
+| Name       | Type           | Description                 |
+| ---------- | -------------- | --------------------------- |
+| type      | `'numKeyboard'` | Type identifier.            |
+| numKeyboard | `object`       | NumKeyboard component config.|
+| input     | `object`       | Input component config.     |
+
+### timePicker
+
+Time picker.
+
+| Name       | Type           | Description                 |
+| ---------- | -------------- | --------------------------- |
+| type      | `'timePicker'` | Type identifier.            |
+| timePicker | `object`       | TimePicker component config.|
+| input     | `object`       | Input component config.     |
+
+### actionSheet
+
+Action sheet.
+
+| Name       | Type           | Description                 |
+| ---------- | -------------- | --------------------------- |
+| type      | `'actionSheet'` | Type identifier.            |
+| actionSheet | `object`       | ActionSheet component config.|
+| input     | `object`       | Input component config.     |
+
+### calendar
+
+Date picker.
+
+| Name     | Type         | Description             |
+| -------- | ------------ | ----------------------- |
+| type    | `'calendar'` | Type identifier.        |
+| calendar | `object`     | Calendar component config.|
+| input   | `object`     | Input component config. |
+
+### picker
+
+Picker.
+
+| Name  | Type    | Description        |
+| ----- | ------- | ------------------ |
+| type | `'picker'` | Type identifier.   |
+| picker | `object` | Picker component config.|
+| input | `object` | Input component config.|
+
+### checkbox
+
+Checkbox group.
+
+| Name     | Type         | Description             |
+| -------- | ------------ | ----------------------- |
+| type    | `'checkbox'` | Type identifier.        |
+| checkbox | `object`     | Checkbox component config.|
+
+### radio
+
+Radio group.
+
+| Name  | Type    | Description       |
+| ----- | ------- | ----------------- |
+| type | `'radio'` | Type identifier.  |
+| radio | `object` | Radio component config.|
+
+### slider
+
+Slider.
+
+| Name   | Type     | Description        |
+| ------ | -------- | ------------------ |
+| type  | `'slider'` | Type identifier.   |
+| slider | `object` | Slider component config.|
+
+### switch
+
+Switch.
+
+| Name   | Type     | Description        |
+| ------ | -------- | ------------------ |
+| type  | `'switch'` | Type identifier.   |
+| switch | `object` | Switch component config.|
+
+### stepper
+
+Stepper.
+
+| Name     | Type         | Description             |
+| -------- | ------------ | ----------------------- |
+| type    | `'stepper'` | Type identifier.        |
+| stepper | `object`     | Stepper component config.|
+
+## FormValueProps
+
+Form value type is `Record<string, FormValueProps>`, where FormValueProps is a union type of all form item values:
+
+| Form Item Type | Value Type                           |
+| -------------- | ------------------------------------ |
+| input          | `string`                             |
+| numKeyboard    | `string`                             |
+| timePicker     | `FormTimePickerValue`                |
+| actionSheet    | `FormActionSheetValue`               |
+| calendar       | `FormCalendarValue`                  |
+| picker         | `FormPickerValue`                    |
+| checkbox       | `string[]`                           |
+| radio          | `string`                             |
+| slider         | `FormSliderValue`                    |
+| switch         | `boolean`                            |
+| stepper        | `number`                             |

+ 49 - 0
docs/mds/components/form/guide.md

@@ -0,0 +1,49 @@
+## 概述
+
+Form 组件用于快速构建完整的表单页面,支持多种表单项类型。通过配置 `form` 数组来定义表单项。
+
+## 支持的表单项类型
+
+Form 组件支持以下 11 种表单项类型:
+
+1. **input** - 文本输入框
+2. **numKeyboard** - 数字键盘
+3. **timePicker** - 时间选择器
+4. **actionSheet** - 操作面板
+5. **calendar** - 日期选择器
+6. **picker** - 选择器
+7. **checkbox** - 复选框组
+8. **radio** - 单选框组
+9. **slider** - 滑块
+10. **switch** - 开关
+11. **stepper** - 步进器
+
+## 卡片布局
+
+设置 `card` 属性可开启卡片布局,适合移动端界面。支持自定义:
+
+- **radius**:圆角大小
+- **shadow**:阴影效果
+- **mx**、**px**:边距
+- **space**:表单项间距
+
+## 按钮配置
+
+- **submitText** / **resetText**:自定义按钮文字
+- **submitButton** / **resetButton**:自定义按钮样式
+- **submitChildren** / **resetChildren**:自定义按钮内容
+- **resetText={null}**:隐藏重置按钮
+
+## 事件
+
+- **onchange**:表单项值变化时触发
+- **onsubmit**:提交时触发
+- **onreset**:重置时触发
+
+## 注意事项
+
+1. **name 唯一性**:每个表单项的 `name` 必须唯一
+2. **必填标识**:`required: true` 会显示红色星号,但组件不包含验证逻辑
+3. **初始值**:`initValue` 需要对应表单项的正确类型
+4. **子组件配置**:可通过 `input`、`picker` 等配置对象定制子组件行为
+5. **返回值类型**:不同表单项返回不同类型的数据

+ 47 - 0
docs/mds/components/form/guide_en.md

@@ -0,0 +1,47 @@
+## Overview
+
+The Form component is used to quickly build complete form pages, supporting various form item types. Configure the `form` array to define form items.
+
+## Supported Form Item Types
+
+The Form component supports the following 11 form item types:
+
+1. **input** - Text input
+2. **numKeyboard** - Number keyboard
+3. **timePicker** - Time picker
+4. **actionSheet** - Action sheet
+5. **calendar** - Date picker
+6. **picker** - Picker
+7. **checkbox** - Checkbox group
+8. **radio** - Radio group
+9. **slider** - Slider
+10. **switch** - Switch
+11. **stepper** - Stepper
+
+## Card Layout
+
+- **radius**: Border radius size
+- **shadow**: Shadow effect
+- **mx**、**px**: Margins
+- **space**: Spacing between form items
+
+## Button Configuration
+
+- **submitText** / **resetText**: Custom button text
+- **submitButton** / **resetButton**: Custom button styles
+- **submitChildren** / **resetChildren**: Custom button content
+- **resetText={null}**: Hide reset button
+
+## Events
+
+- **onchange**: Triggered when form item value changes
+- **onsubmit**: Triggered on submit
+- **onreset**: Triggered on reset
+
+## Notes
+
+1. **name Uniqueness**: Each form item's `name` must be unique
+2. **Required Flag**: `required: true` displays a red asterisk, but the component does not include validation logic
+3. **Initial Value**: `initValue` must match the correct type for each form item
+4. **Sub-component Configuration**: Sub-components can be customized through configuration objects like `input`, `picker`, etc.
+5. **Return Value Types**: Different form items return different types of data

+ 0 - 0
docs/mds/components/form/version.md


+ 0 - 0
docs/mds/components/form/version_en.md


+ 13 - 2
packages/stdf/src/data/menuList.ts

@@ -186,7 +186,8 @@ export const menuList: MenuList[] = [
 				nav: 'asyncPicker',
 				tip: '错过的话,就请错过一辈子吧!',
 				tip_en: 'If you miss it, please miss it for a lifetime!',
-				alias: 'asyncPicker|异步选择器 | 异步|asyncPicker 异步选择器|asyncPicker 异步选择器|async picker|asyncpicker|异步 picker|异步 picker'
+				alias:
+					'asyncPicker|异步选择器 | 异步|asyncPicker 异步选择器|asyncPicker 异步选择器|async picker|asyncpicker|异步 picker|异步 picker'
 			},
 			{
 				title: '日历 Calendar',
@@ -208,6 +209,15 @@ export const menuList: MenuList[] = [
 				alias:
 					'checkbox|复选框 | 复选|checkbox 复选框|checkbox 复选框 | 复选按钮|checkbox 复选按钮|checkbox 复选按钮 | 多选框 | 多选|checkbox 多选框|checkbox 多选框 | 多选按钮|checkbox 多选按钮|checkbox 多选按钮'
 			},
+			{
+				title: '表单 Form',
+				title_zh: '表单',
+				title_en: 'Form',
+				nav: 'form',
+				tip: '别让用户思考,除非你想让他们逃跑。',
+				tip_en: 'Do not make users think, unless you want them to run away.',
+				alias: 'form|表单'
+			},
 			{
 				title: '输入框 Input',
 				title_zh: '输入框',
@@ -362,7 +372,8 @@ export const menuList: MenuList[] = [
 				nav: 'swiper',
 				tip: '人世间悲喜烂剧,昼夜轮播不停。',
 				tip_en: 'The ups and downs of life, day and night, are not stopping.',
-				alias: 'swiper|轮播 | 轮|播|swiper 轮播|swiper 轮播 | 轮播图|swiper 轮播图|swiper 轮播图 | 走马灯|swiper 走马灯|swiper 走马灯|carousel'
+				alias:
+					'swiper|轮播 | 轮|播|swiper 轮播|swiper 轮播 | 轮播图|swiper 轮播图|swiper 轮播图 | 走马灯|swiper 走马灯|swiper 走马灯|carousel'
 			}
 		]
 	},

+ 462 - 0
packages/stdf/src/lib/components/form/Form.svelte

@@ -0,0 +1,462 @@
+<script lang="ts">
+	import { getContext } from 'svelte';
+	import Input from '../input/Input.svelte';
+	import TimePicker from '../timePicker/TimePicker.svelte';
+	import ActionSheet from '../actionSheet/ActionSheet.svelte';
+	import Calendar from '../calendar/Calendar.svelte';
+	import NumKeyboard from '../numKeyboard/NumKeyboard.svelte';
+	import Picker from '../picker/Picker.svelte';
+	import Checkbox from '../checkbox/Checkbox.svelte';
+	import Radio from '../radio/Radio.svelte';
+	import Slider from '../slider/Slider.svelte';
+	import Switch from '../switch/Switch.svelte';
+	import Stepper from '../stepper/Stepper.svelte';
+	import Button from '../button/Button.svelte';
+	import { zh_CN, type LangProps } from '../../lang/index.js';
+	import type {
+		FormProps,
+		FormValueProps,
+		FormTimePickerValue,
+		FormCalendarValue,
+		FormActionSheetValue,
+		FormPickerValue,
+		FormSliderValue
+	} from '../../types/index.js';
+
+	// 当前语言
+	// current language
+	const currentLang = (getContext('STDF_lang') || zh_CN) as LangProps;
+	const formLang: LangProps['form'] = currentLang.form;
+
+	let {
+		form,
+		onchange,
+		submitText = formLang.submit,
+		resetText = null,
+		onsubmit,
+		submitButton,
+		resetButton,
+		onreset,
+		submitChildren,
+		resetChildren,
+		card = false,
+		mx = '4',
+		space = '0',
+		radius = 'xl',
+		px = '2',
+		shadow = 'sm'
+	}: FormProps = $props();
+
+	let formInner = $state(
+		form.map((item) => {
+			const baseItem = {
+				showPopup: false,
+				data: null as unknown,
+				// 保存初始值用于重置 / save init value for reset
+				initValue: item.initValue,
+				...item
+			};
+
+			if (item.type === 'slider') {
+				const userValueRange = item.slider?.valueRange as [number, number];
+				const userValue = item.slider?.value as number;
+
+				return {
+					...baseItem,
+					value: item.slider?.isRange
+						? ({ valueRange: userValueRange || (item.initValue as [number, number]) || [20, 60] } as FormSliderValue)
+						: ({ value: userValue || (item.initValue as number) || 40 } as FormSliderValue),
+					slider: {
+						...item.slider,
+						...(item.slider?.isRange
+							? {
+									startValue: userValueRange?.[0] || (item.initValue as [number, number])?.[0] || 20,
+									endValue: userValueRange?.[1] || (item.initValue as [number, number])?.[1] || 60,
+									valueRange: userValueRange || (item.initValue as [number, number]) || [20, 60]
+								}
+							: {
+									value: userValue || (item.initValue as number) || 40
+								})
+					}
+				};
+			}
+
+			return {
+				...baseItem,
+				value:
+					item.type === 'checkbox'
+						? ([] as string[])
+						: item.type === 'switch'
+							? false
+							: item.type === 'stepper'
+								? (item.initValue as number) || 0
+								: item.type === 'timePicker'
+									? ({ timeStr: '', timeObj: undefined } as FormTimePickerValue)
+									: item.type === 'actionSheet'
+										? ({ action: undefined, index: undefined } as FormActionSheetValue)
+										: item.type === 'picker'
+											? ({ items: [], indexs: [] } as FormPickerValue)
+											: item.type === 'calendar'
+												? ({ dates: [] } as FormCalendarValue)
+												: (item.initValue as string) || ''
+			};
+		})
+	);
+	let model = $state<Record<string, FormValueProps>>({});
+	// 统一的 onchange 处理函数 / unified onchange handler
+	const handleFormChange = (currentItem: (typeof formInner)[0], currentValue: unknown) => {
+		// 更新当前项的数据 / update current item data
+		// currentItem.data = currentValue;
+		model[currentItem.name] = currentValue as FormValueProps;
+		onchange?.(model);
+	};
+	const submitFunc = () => {
+		onsubmit?.(model as Record<string, FormValueProps>);
+	};
+	const resetFunc = () => {
+		// 逐个重置每个表单项,避免完全重新赋值导致的页面滚动 / reset each form item to avoid page scroll caused by full reassignment
+		const newModel: Record<string, FormValueProps> = {};
+		formInner.forEach((item) => {
+			if (item.type === 'slider') {
+				const userValueRange = item.slider?.valueRange as [number, number];
+				const userValue = item.slider?.value as number;
+
+				item.value = item.slider?.isRange
+					? ({ valueRange: userValueRange || (item.initValue as [number, number]) || [20, 60] } as FormSliderValue)
+					: ({ value: userValue || (item.initValue as number) || 40 } as FormSliderValue);
+
+				// 同时更新 slider 属性以确保重置生效 / also update slider properties to ensure reset takes effect
+				if (item.slider?.isRange) {
+					const resetRange = userValueRange || (item.initValue as [number, number]) || [20, 60];
+					item.slider = {
+						...item.slider,
+						startValue: resetRange[0],
+						endValue: resetRange[1],
+						valueRange: resetRange
+					};
+				} else {
+					const resetValue = userValue || (item.initValue as number) || 40;
+					item.slider = {
+						...item.slider,
+						value: resetValue
+					};
+				}
+			} else if (item.type === 'checkbox') {
+				item.value = [] as string[];
+			} else if (item.type === 'switch') {
+				item.value = false;
+			} else if (item.type === 'stepper') {
+				item.value = (item.initValue as number) || 0;
+			} else if (item.type === 'timePicker') {
+				item.value = { timeStr: '', timeObj: undefined } as FormTimePickerValue;
+			} else if (item.type === 'actionSheet') {
+				item.value = { action: undefined, index: undefined } as FormActionSheetValue;
+			} else if (item.type === 'picker') {
+				item.value = { items: [], indexs: [] } as FormPickerValue;
+			} else if (item.type === 'calendar') {
+				item.value = { dates: [] } as FormCalendarValue;
+			} else {
+				item.value = (item.initValue as string) || '';
+			}
+
+			// 同时更新 model / also update model
+			newModel[item.name] = item.value as FormValueProps;
+			item.showPopup = false;
+			item.data = null as unknown;
+		});
+		// 更新 model 对象 / update model object
+		model = newModel;
+		onchange?.(model);
+		onreset?.();
+	};
+
+	// 间距 space / spacing
+	const spaceClass = { '0': 'space-y-0', '1': 'space-y-1', '2': 'space-y-2', '4': 'space-y-4', '6': 'space-y-6', '8': 'space-y-8' };
+	// 卡片圆角 card radius / card border radius
+	const radiusClass = {
+		sm: 'rounded-sm',
+		md: 'rounded-md',
+		lg: 'rounded-lg',
+		xl: 'rounded-xl',
+		'2xl': 'rounded-2xl',
+		'3xl': 'rounded-3xl',
+		'4xl': 'rounded-4xl'
+	};
+	// 水平外边距 mx / horizontal margin
+	const mxClass = { '2': 'mx-2', '3': 'mx-3', '4': 'mx-4', '6': 'mx-6', '8': 'mx-8' };
+	// 内边距 px / padding
+	const pxClass = { '0': 'px-0', '1': 'px-1', '2': 'px-2', '4': 'px-4', '6': 'px-6' };
+	// 阴影 shadow / shadow
+	const shadowClass = {
+		none: 'shadow-none',
+		xs: 'shadow-xs dark:shadow-white/10',
+		sm: 'shadow-sm dark:shadow-white/10',
+		md: 'shadow-md dark:shadow-white/10',
+		lg: 'shadow-lg dark:shadow-white/10',
+		xl: 'shadow-xl dark:shadow-white/10',
+		'2xl': 'shadow-2xl dark:shadow-white/10'
+	};
+</script>
+
+<div
+	class="{spaceClass[space] || 'space-y-0'}{card
+		? ` ${radiusClass[radius] || 'rounded-xl'} ${mxClass[mx] || 'mx-4'} ${pxClass[px] || 'px-2'} ${shadowClass[shadow] || shadowClass.sm} mb-2 bg-white py-2 dark:bg-black`
+		: ''}"
+>
+	{#each formInner as item (item.name)}
+		{#if item.type === 'input' || !item.type}
+			<Input
+				title={item.label}
+				bind:value={item.value as string}
+				clear
+				required={item.required}
+				onclear={() => {
+					item.value = '';
+					handleFormChange(item, '');
+				}}
+				onchange={() => handleFormChange(item, item.value)}
+				{...'input' in item ? item.input : {}}
+			/>
+		{:else if item.type === 'timePicker'}
+			<Input
+				title={item.label}
+				select
+				value={(item.value as FormTimePickerValue)?.timeStr || ''}
+				clear
+				required={item.required}
+				onfocus={() => {
+					item.showPopup = true;
+				}}
+				onclear={() => {
+					item.value = { timeStr: '', timeObj: undefined };
+					handleFormChange(item, { timeStr: '', timeObj: undefined });
+				}}
+				{...item?.input}
+			/>
+			<TimePicker
+				bind:visible={item.showPopup}
+				onconfirm={(timeStr, timeObj) => {
+					item.value = { timeStr, timeObj };
+					handleFormChange(item, { timeStr, timeObj });
+				}}
+				{...item.timePicker}
+			/>
+		{:else if item.type === 'actionSheet'}
+			<Input
+				title={item.label}
+				select
+				value={(item.value as FormActionSheetValue)?.action?.content || ''}
+				clear
+				required={item.required}
+				onfocus={() => {
+					item.showPopup = true;
+				}}
+				onclear={() => {
+					item.value = { action: undefined, index: undefined };
+					handleFormChange(item, { action: undefined, index: undefined });
+				}}
+				{...item?.input}
+			/>
+			<ActionSheet
+				bind:visible={item.showPopup}
+				onclickAction={(index: number, action) => {
+					item.value = { action, index };
+					handleFormChange(item, { action, index });
+				}}
+				{...item.actionSheet}
+			/>
+		{:else if item.type === 'calendar'}
+			<Input
+				title={item.label}
+				select
+				value={(() => {
+					const dates = (item.value as FormCalendarValue)?.dates;
+					if (!dates || dates.length === 0) return '';
+					// 如果是范围选择,格式为 "开始日期 - 结束日期" / if range selection, format as "start date - end date"
+					const isRange = item.calendar?.mode === 'range';
+					if (isRange && dates.length >= 2) {
+						return `${dates[0]} - ${dates[1]}`;
+					}
+					return dates.join(',');
+				})()}
+				clear
+				required={item.required}
+				onfocus={() => {
+					item.showPopup = true;
+				}}
+				onclear={() => {
+					item.value = { dates: [] };
+					handleFormChange(item, { dates: [] });
+				}}
+				{...item?.input}
+			/>
+			<Calendar
+				bind:visible={item.showPopup}
+				onconfirm={(dates) => {
+					item.value = { dates };
+					handleFormChange(item, { dates });
+				}}
+				clear={false}
+				{...item.calendar}
+			/>
+		{:else if item.type === 'numKeyboard'}
+			<Input
+				title={item.label}
+				select
+				bind:value={item.value as string}
+				clear
+				required={item.required}
+				onfocus={() => {
+					item.showPopup = true;
+				}}
+				onclear={() => {
+					item.value = '';
+					handleFormChange(item, '');
+				}}
+				{...item.input}
+			/>
+			<NumKeyboard
+				bind:visible={item.showPopup}
+				onclick={(key) => {
+					if (key === 'close' || key === 'done') {
+						item.showPopup = false;
+					} else if (key === 'delete') {
+						item.value = (item.value as string).slice(0, -1);
+					} else {
+						item.value = (item.value as string) + key;
+					}
+					handleFormChange(item, item.value);
+				}}
+				{...item.numKeyboard}
+			/>
+		{:else if item.type === 'picker'}
+			<Input
+				title={item.label}
+				select
+				value={(item.value as FormPickerValue)?.items?.map((item) => item.label).join(' / ') || ''}
+				clear
+				required={item.required}
+				onfocus={() => {
+					item.showPopup = true;
+				}}
+				onclear={() => {
+					item.value = { items: [], indexs: [] };
+					handleFormChange(item, { items: [], indexs: [] });
+				}}
+				{...item?.input}
+			/>
+			<Picker
+				bind:visible={item.showPopup}
+				datas={item.picker?.datas || []}
+				onconfirm={(items, indexs) => {
+					item.value = { items, indexs };
+					handleFormChange(item, { items, indexs });
+				}}
+				onclose={() => {
+					item.showPopup = false;
+				}}
+				{...item.picker}
+			/>
+		{:else if item.type === 'checkbox'}
+			<div class="p-2">
+				<div class="mb-2 flex justify-between px-2">
+					<div class="relative mb-1 text-sm font-semibold">
+						{#if item.required}
+							<span class="text-error absolute -left-2.5 text-base">*</span>
+						{/if}
+						{item.label}
+					</div>
+					<div class="flex space-x-2 text-xs"></div>
+				</div>
+				<Checkbox
+					data={item.checkbox?.data || []}
+					{...item.checkbox}
+					bind:checkeds={item.value as string[]}
+					onchange={(checkeds: string[]) => handleFormChange(item, checkeds)}
+				/>
+			</div>
+		{:else if item.type === 'radio'}
+			<div class="p-2">
+				<div class="mb-2 flex justify-between px-2">
+					<div class="relative mb-1 text-sm font-semibold">
+						{#if item.required}
+							<span class="text-error absolute -left-2.5 text-base">*</span>
+						{/if}
+						{item.label}
+					</div>
+					<div class="flex space-x-2 text-xs"></div>
+				</div>
+				<Radio
+					data={item.radio?.data || []}
+					{...item.radio}
+					bind:value={item.value as string}
+					onchange={(value: string) => handleFormChange(item, value)}
+				/>
+			</div>
+		{:else if item.type === 'slider'}
+			<div class="p-2">
+				<div class="mb-2 flex justify-between px-2">
+					<div class="relative mb-1 text-sm font-semibold">
+						{#if item.required}
+							<span class="text-error absolute -left-2.5 text-base">*</span>
+						{/if}
+						{item.label}
+					</div>
+					<div class="flex space-x-2 text-xs"></div>
+				</div>
+				<div class="mx-4">
+					<Slider
+						{...item.slider}
+						onchange={(value, valueRange) => {
+							if (item.slider?.isRange) {
+								if (valueRange) {
+									(item.value as FormSliderValue).valueRange = valueRange;
+									handleFormChange(item, { valueRange });
+								}
+							} else {
+								(item.value as FormSliderValue).value = value;
+								handleFormChange(item, { value });
+							}
+						}}
+					/>
+				</div>
+			</div>
+		{:else if item.type === 'switch'}
+			<div class="p-2">
+				<div class="mb-2 flex justify-between px-2">
+					<div class="relative mb-1 text-sm font-semibold">
+						{#if item.required}
+							<span class="text-error absolute -left-2.5 text-base">*</span>
+						{/if}
+						{item.label}
+					</div>
+					<div class="flex space-x-2 text-xs"></div>
+				</div>
+				<Switch {...item.switch} bind:active={item.value as boolean} onchange={(value: boolean) => handleFormChange(item, value)} />
+			</div>
+		{:else if item.type === 'stepper'}
+			<div class="p-2">
+				<div class="mb-2 flex justify-between px-2">
+					<div class="relative mb-1 text-sm font-semibold">
+						{#if item.required}
+							<span class="text-error absolute -left-2.5 text-base">*</span>
+						{/if}
+						{item.label}
+					</div>
+					<div class="flex space-x-2 text-xs"></div>
+				</div>
+				<Stepper {...item.stepper} bind:value={item.value as number} onchange={(value: number) => handleFormChange(item, value)} />
+			</div>
+		{:else}{/if}
+	{/each}
+</div>
+{#if submitChildren}
+	{@render submitChildren?.()}
+{:else if submitText}
+	<Button onclick={submitFunc} {...submitButton}>{submitText}</Button>
+{:else}{/if}
+{#if resetChildren}
+	{@render resetChildren?.()}
+{:else if resetText}
+	<Button fill="lineTheme" type="button" onclick={resetFunc} {...resetButton}>{resetText}</Button>
+{:else}{/if}

+ 66 - 29
packages/stdf/src/lib/components/picker/Picker.svelte

@@ -70,43 +70,51 @@
 	const initFn = () => {
 		// 对 datas 处理,如果没有设置 initIndex 则默认为 0,如果没有设置 showRow 则默认为 5
 		// Process datas, if initIndex is not set, it is default to 0, if showRow is not set, it is default to 5
-		newDatas = newDatas.map((item, index) => {
-			if (!item.initIndex) {
-				(item as PickerDatasProps).initIndex = 0;
+		const processedDatas = newDatas.map((item, index) => {
+			// 创建一个新的对象,避免直接修改响应式状态
+			// Create a new object to avoid directly modifying reactive state
+			const processedItem = { ...item };
+
+			if (!processedItem.initIndex) {
+				(processedItem as PickerDatasProps).initIndex = 0;
 			}
-			if (!item.showRow) {
-				item.showRow = 5;
+			if (!processedItem.showRow) {
+				processedItem.showRow = 5;
 			}
-			if (!(item as PickerDatasProps).lastSelectedIndex) {
-				(item as PickerDatasProps).lastSelectedIndex = 0;
+			if (!(processedItem as PickerDatasProps).lastSelectedIndex) {
+				(processedItem as PickerDatasProps).lastSelectedIndex = 0;
 			}
-			if (!item.flex) {
-				item.flex = 1;
+			if (!processedItem.flex) {
+				processedItem.flex = 1;
 			}
-			if (!item.align) {
-				item.align = 'center';
+			if (!processedItem.align) {
+				processedItem.align = 'center';
 			}
 			if (isLinkage) {
 				if (linkageInitIndexs[index]) {
-					item.initIndex = linkageInitIndexs[index];
+					processedItem.initIndex = linkageInitIndexs[index];
 				} else {
-					item.initIndex = 0;
+					processedItem.initIndex = 0;
 				}
 				if (linkageShowRows[index]) {
-					(item as PickerDatasProps).showRow = linkageShowRows[index] as 3 | 5 | 7;
+					(processedItem as PickerDatasProps).showRow = linkageShowRows[index] as 3 | 5 | 7;
 				}
 				if (linkageFlexs[index]) {
-					item.flex = linkageFlexs[index];
+					processedItem.flex = linkageFlexs[index];
 				}
 				if (linkageAligns[index]) {
-					item.align = linkageAligns[index];
+					processedItem.align = linkageAligns[index];
 				}
-				if (!item.lastSelectedIndex) {
-					item.lastSelectedIndex = 0;
+				if (!processedItem.lastSelectedIndex) {
+					processedItem.lastSelectedIndex = 0;
 				}
 			}
-			return item;
+			return processedItem;
 		}) as PickerDatasProps[];
+
+		// 重新赋值 newDatas
+		// Reassign newDatas
+		newDatas = processedDatas;
 		// 滚动结束时选中项组成的数组
 		// An array of selected items when scrolling ends
 		scrollEndIndexs = newDatas.map((item: PickerDatasProps | PickerDataChildProps) => item.initIndex as number);
@@ -174,10 +182,15 @@
 			// Take each item in tempItems out according to the index of lastSelectedIndexs to form a new array items
 			items = tempItems.map((item: PickerDatasProps[] | PickerDataChildProps[], index: number) => {
 				const selectedIndex = lastSelectedIndexs[index];
-				if (Array.isArray(item)) {
-					return item[selectedIndex] as { [key: string]: string };
+				if (Array.isArray(item) && item[selectedIndex]) {
+					const selectedItem = item[selectedIndex] as PickerDataChildProps;
+					// 根据 linkageLabelKeys 获取正确的 label
+					// Get the correct label according to linkageLabelKeys
+					const labelKey = linkageLabelKeys[index] || 'label';
+					const label = selectedItem[labelKey] || selectedItem.label || '';
+					return { label: label as string };
 				}
-				return item;
+				return { label: '' };
 			});
 		} else {
 			// 循环 datas 与 scrollEndIndexs,按照 scrollEndIndexs 将 datas 中的 data 对应的��组成一个新数组
@@ -203,9 +216,12 @@
 		if (isLinkage) {
 			// 任何列滚动之后,使传入的 linkageInitIndexs 都会失效,将所有下级的初始选中项设置为 0
 			// After any column scrolls, the linkageInitIndexs passed in will all be invalid, and set the initial selected item of all lower levels to 0
-			for (let i = col + 1; i < newDatas.length; i++) {
-				newDatas[i].initIndex = 0;
-			}
+			newDatas = newDatas.map((item, index) => {
+				if (index > col) {
+					return { ...item, initIndex: 0 };
+				}
+				return item;
+			}) as PickerDatasProps[];
 			// 递归计算当前列的数据
 			// Recursively calculate the data of the current column
 			if (col === 0) {
@@ -214,11 +230,15 @@
 				allLevelData[0] = datas as PickerDatasProps[];
 			} else {
 				preLevelData = allLevelData[col - 1] as PickerDatasProps[];
-				if (preLevelData[scrollEndIndexs[col - 1]]) {
+				if (preLevelData && preLevelData[scrollEndIndexs[col - 1]]) {
 					const children = preLevelData[scrollEndIndexs[col - 1]][linkageChildrenKey as keyof PickerDatasProps] as PickerDataChildProps[];
 					currentLevelData = Array.isArray(children) ? (children as PickerDataChildProps[]) : [];
+					// 更新 allLevelData 当前级别的数据
+					// Update allLevelData for current level
+					allLevelData[col] = currentLevelData;
 				} else {
 					currentLevelData = [];
+					allLevelData[col] = [];
 				}
 			}
 			// 递归计算后面的所有列数据
@@ -240,10 +260,22 @@
 						);
 						// 将数据置空,此列数据为空,此列将立即消失,然后通过 setTimeout 立即设置数据,使得数据更新后,此列才会出现
 						// Set the data to empty, the data of this column is empty, this column will disappear immediately, and then set the data immediately through setTimeout, so that the data is updated, this column will appear
-						newDatas[nextCol].data = [];
+						newDatas = newDatas.map((item, idx) => {
+							if (idx === nextCol) {
+								return { ...item, data: [] };
+							}
+							return item;
+						}) as PickerDatasProps[];
 						setTimeout(() => {
-							newDatas[nextCol].data = nextData;
+							newDatas = newDatas.map((item, idx) => {
+								if (idx === nextCol) {
+									return { ...item, data: nextData };
+								}
+								return item;
+							}) as PickerDatasProps[];
 						});
+						// 确保 allLevelData 正确存储当前级别的完整数据
+						// Ensure allLevelData correctly stores the complete data for current level
 						allLevelData[nextCol] = nextLevelData;
 						recursionFunc(nextCol, nextLevelData);
 					} else {
@@ -251,7 +283,12 @@
 						// If there is no data in the next level, set the data of the next level to empty
 						// 也可以用来解决数据层级超级大的时候,递归计算数据的性能问题,暂时将后面的数据置空,等到有数据的时候再设置,避免选择数据与视图不同步的问题
 						// It can also be used to solve the performance problem of recursive calculation of data when the data hierarchy is super large. Temporarily set the data behind to empty, and set it when there is data, to avoid the problem that the selected data and the view are not synchronized
-						newDatas[nextCol].data = [];
+						newDatas = newDatas.map((item, idx) => {
+							if (idx === nextCol) {
+								return { ...item, data: [] };
+							}
+							return item;
+						}) as PickerDatasProps[];
 					}
 				}
 			};

+ 1 - 0
packages/stdf/src/lib/index.ts

@@ -12,6 +12,7 @@ export { default as CheckboxItem } from './components/checkbox/CheckboxItem.svel
 export { default as Checkbox } from './components/checkbox/Checkbox.svelte';
 export { default as Dialog } from './components/dialog/Dialog.svelte';
 export { default as Divider } from './components/divider/Divider.svelte';
+export { default as Form } from './components/form/Form.svelte';
 export { default as Grid } from './components/grids/Grid.svelte';
 export { default as Grids } from './components/grids/Grids.svelte';
 export { default as Icon } from './components/icon/Icon.svelte';

+ 5 - 1
packages/stdf/src/lib/lang/ar_EG.ts

@@ -21,7 +21,8 @@ const ar_EG: LangProps = {
 		secondaryText: 'إلغاء'
 	},
 	input: {
-		pleaseInput: 'الرجاء إدخال'
+		pleaseInput: 'الرجاء إدخال',
+		pleaseSelect: 'الرجاء الاختيار'
 	},
 	modal: {
 		title: 'العنوان',
@@ -77,6 +78,9 @@ const ar_EG: LangProps = {
 		currentWeekText: 'هذا الأسبوع',
 		currentMonthText: 'هذا الشهر',
 		currentQuarterText: 'هذه الفصل'
+	},
+	form: {
+		submit: 'إرسال'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/az_AZ.ts

@@ -21,7 +21,8 @@ const az_AZ: LangProps = {
 		secondaryText: 'Ləğv et'
 	},
 	input: {
-		pleaseInput: 'Daxil edin'
+		pleaseInput: 'Daxil edin',
+		pleaseSelect: 'Zəhmət olmasa seçin'
 	},
 	modal: {
 		title: 'Başlıq',
@@ -77,6 +78,9 @@ const az_AZ: LangProps = {
 		currentWeekText: 'Bu həftə',
 		currentMonthText: 'Bu ay',
 		currentQuarterText: 'Bu rəbə'
+	},
+	form: {
+		submit: 'Göndər'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/bg_BG.ts

@@ -21,7 +21,8 @@ const bg_BG: LangProps = {
 		secondaryText: 'Откажи'
 	},
 	input: {
-		pleaseInput: 'Моля, въведете'
+		pleaseInput: 'Моля, въведете',
+		pleaseSelect: 'Моля изберете'
 	},
 	modal: {
 		title: 'Заглавие',
@@ -77,6 +78,9 @@ const bg_BG: LangProps = {
 		currentWeekText: 'Тази седмица',
 		currentMonthText: 'Този месец',
 		currentQuarterText: 'Това тримесечие'
+	},
+	form: {
+		submit: 'Изпрати'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/bn_BD.ts

@@ -21,7 +21,8 @@ const bn_BD: LangProps = {
 		secondaryText: 'না'
 	},
 	input: {
-		pleaseInput: 'অনুগ্রহপূর্বক প্রবেশ করুন'
+		pleaseInput: 'অনুগ্রহপূর্বক প্রবেশ করুন',
+		pleaseSelect: 'অনুগ্রহ করে নির্বাচন করুন'
 	},
 	modal: {
 		title: 'শিরোনাম',
@@ -90,6 +91,9 @@ const bn_BD: LangProps = {
 		currentWeekText: 'এই সপ্তাহে',
 		currentMonthText: 'এই মাসে',
 		currentQuarterText: 'এই ত্রৈমাসিকে'
+	},
+	form: {
+		submit: 'জমা দিন'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/ca_ES.ts

@@ -21,7 +21,8 @@ const ca_ES: LangProps = {
 		secondaryText: 'Cancel·lar'
 	},
 	input: {
-		pleaseInput: 'Si us plau, introdueixi'
+		pleaseInput: 'Si us plau, introdueixi',
+		pleaseSelect: 'Si us plau, trieu'
 	},
 	modal: {
 		title: 'Títol',
@@ -77,6 +78,9 @@ const ca_ES: LangProps = {
 		currentWeekText: 'Aquesta setmana',
 		currentMonthText: 'Aquest mes',
 		currentQuarterText: 'Aquest trimestre'
+	},
+	form: {
+		submit: 'Enviar'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/cs_CZ.ts

@@ -21,7 +21,8 @@ const cs_CZ: LangProps = {
 		secondaryText: 'Zrušit'
 	},
 	input: {
-		pleaseInput: 'Prosím, zadejte'
+		pleaseInput: 'Prosím, zadejte',
+		pleaseSelect: 'Prosím vyberte'
 	},
 	modal: {
 		title: 'Název',
@@ -77,6 +78,9 @@ const cs_CZ: LangProps = {
 		currentWeekText: 'Tento týden',
 		currentMonthText: 'Tento měsíc',
 		currentQuarterText: 'Toto čtvrtletí'
+	},
+	form: {
+		submit: 'Odeslat'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/da_DK.ts

@@ -21,7 +21,8 @@ const da_DK: LangProps = {
 		secondaryText: 'Annuller'
 	},
 	input: {
-		pleaseInput: 'Indtast venligst'
+		pleaseInput: 'Indtast venligst',
+		pleaseSelect: 'Vælg venligst'
 	},
 	modal: {
 		title: 'Titel',
@@ -77,6 +78,9 @@ const da_DK: LangProps = {
 		currentWeekText: 'Denne uge',
 		currentMonthText: 'Denne måned',
 		currentQuarterText: 'Dette kvartal'
+	},
+	form: {
+		submit: 'Indsend'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/de_DE.ts

@@ -21,7 +21,8 @@ const de_DE: LangProps = {
 		secondaryText: 'Abbrechen'
 	},
 	input: {
-		pleaseInput: 'Bitte geben Sie ein'
+		pleaseInput: 'Bitte geben Sie ein',
+		pleaseSelect: 'Bitte wählen'
 	},
 	modal: {
 		title: 'Titel',
@@ -77,6 +78,9 @@ const de_DE: LangProps = {
 		currentWeekText: 'Diese Woche',
 		currentMonthText: 'Dieser Monat',
 		currentQuarterText: 'Dieses Quartal'
+	},
+	form: {
+		submit: 'Senden'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/el_GR.ts

@@ -21,7 +21,8 @@ const el_GR: LangProps = {
 		secondaryText: 'Ακύρωση'
 	},
 	input: {
-		pleaseInput: 'Παρακαλώ εισάγετε'
+		pleaseInput: 'Παρακαλώ εισάγετε',
+		pleaseSelect: 'Παρακαλώ επιλέξτε'
 	},
 	modal: {
 		title: 'Τίτλος',
@@ -90,6 +91,9 @@ const el_GR: LangProps = {
 		currentWeekText: 'Αυτήν την εβδομάδα',
 		currentMonthText: 'Αυτό το μήνα',
 		currentQuarterText: 'Αυτό το τρίμηνο'
+	},
+	form: {
+		submit: 'Υποβολή'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/en_GB.ts

@@ -21,7 +21,8 @@ const en_GB: LangProps = {
 		secondaryText: 'Cancel'
 	},
 	input: {
-		pleaseInput: 'Please input'
+		pleaseInput: 'Please input',
+		pleaseSelect: 'Please select'
 	},
 	modal: {
 		title: 'Title',
@@ -90,6 +91,9 @@ const en_GB: LangProps = {
 		currentWeekText: 'This week',
 		currentMonthText: 'This month',
 		currentQuarterText: 'This quarter'
+	},
+	form: {
+		submit: 'Submit'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/en_US.ts

@@ -21,7 +21,8 @@ const en_US: LangProps = {
 		secondaryText: 'Cancel'
 	},
 	input: {
-		pleaseInput: 'Please enter'
+		pleaseInput: 'Please enter',
+		pleaseSelect: 'Please select'
 	},
 	modal: {
 		title: 'Title',
@@ -90,6 +91,9 @@ const en_US: LangProps = {
 		currentWeekText: 'This week',
 		currentMonthText: 'This month',
 		currentQuarterText: 'This quarter'
+	},
+	form: {
+		submit: 'Submit'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/es_ES.ts

@@ -21,7 +21,8 @@ const es_ES: LangProps = {
 		secondaryText: 'Cancelar'
 	},
 	input: {
-		pleaseInput: 'Por favor, introduzca'
+		pleaseInput: 'Por favor, introduzca',
+		pleaseSelect: 'Por favor seleccione'
 	},
 	modal: {
 		title: 'Título',
@@ -90,6 +91,9 @@ const es_ES: LangProps = {
 		currentWeekText: 'Esta semana',
 		currentMonthText: 'Este mes',
 		currentQuarterText: 'Este trimestre'
+	},
+	form: {
+		submit: 'Enviar'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/et_EE.ts

@@ -21,7 +21,8 @@ const et_EE: LangProps = {
 		secondaryText: 'Tühista'
 	},
 	input: {
-		pleaseInput: 'Palun sisesta'
+		pleaseInput: 'Palun sisesta',
+		pleaseSelect: 'Palun valige'
 	},
 	modal: {
 		title: 'Pealkiri',
@@ -90,6 +91,9 @@ const et_EE: LangProps = {
 		currentWeekText: 'See nädal',
 		currentMonthText: 'See kuu',
 		currentQuarterText: 'See kvartal'
+	},
+	form: {
+		submit: 'Saada'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/eu_ES.ts

@@ -21,7 +21,8 @@ const eu_ES: LangProps = {
 		secondaryText: 'Utzi'
 	},
 	input: {
-		pleaseInput: 'Mesedez sartu'
+		pleaseInput: 'Mesedez sartu',
+		pleaseSelect: 'Mesedez aukeratu'
 	},
 	modal: {
 		title: 'Izenburua',
@@ -90,6 +91,9 @@ const eu_ES: LangProps = {
 		currentWeekText: 'Aste hau',
 		currentMonthText: 'Hilabete hau',
 		currentQuarterText: 'Gertaera hau'
+	},
+	form: {
+		submit: 'Bidali'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/fa_IR.ts

@@ -21,7 +21,8 @@ const fa_IR: LangProps = {
 		secondaryText: 'لغو'
 	},
 	input: {
-		pleaseInput: 'لطفا وارد کنید'
+		pleaseInput: 'لطفا وارد کنید',
+		pleaseSelect: 'لطفاً انتخاب کنید'
 	},
 	modal: {
 		title: 'عنوان',
@@ -77,6 +78,9 @@ const fa_IR: LangProps = {
 		currentWeekText: 'هفته جاری',
 		currentMonthText: 'ماه جاری',
 		currentQuarterText: 'سه ماهه جاری'
+	},
+	form: {
+		submit: 'ارسال'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/fi_FI.ts

@@ -21,7 +21,8 @@ const fi_FI: LangProps = {
 		secondaryText: 'Peruuta'
 	},
 	input: {
-		pleaseInput: 'Kirjoita tähän'
+		pleaseInput: 'Kirjoita tähän',
+		pleaseSelect: 'Valitse'
 	},
 	modal: {
 		title: 'Otsikko',
@@ -90,6 +91,9 @@ const fi_FI: LangProps = {
 		currentWeekText: 'Nykyinen viikko',
 		currentMonthText: 'Nykyinen kuukausi',
 		currentQuarterText: 'Nykyinen neljännesvuosi'
+	},
+	form: {
+		submit: 'Lähetä'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/fr_BE.ts

@@ -21,7 +21,8 @@ const fr_BE: LangProps = {
 		secondaryText: 'Annuler'
 	},
 	input: {
-		pleaseInput: 'Veuillez renseigner'
+		pleaseInput: 'Veuillez renseigner',
+		pleaseSelect: 'Veuillez sélectionner'
 	},
 	modal: {
 		title: 'Titre',
@@ -90,6 +91,9 @@ const fr_BE: LangProps = {
 		currentWeekText: 'Semaine en cours',
 		currentMonthText: 'Mois en cours',
 		currentQuarterText: 'Trimestre en cours'
+	},
+	form: {
+		submit: 'Soumettre'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/fr_CA.ts

@@ -21,7 +21,8 @@ const fr_CA: LangProps = {
 		secondaryText: 'Annuler'
 	},
 	input: {
-		pleaseInput: 'Veuillez renseigner'
+		pleaseInput: 'Veuillez renseigner',
+		pleaseSelect: 'Veuillez sélectionner'
 	},
 	modal: {
 		title: 'Titre',
@@ -90,6 +91,9 @@ const fr_CA: LangProps = {
 		currentWeekText: 'Semaine en cours',
 		currentMonthText: 'Mois en cours',
 		currentQuarterText: 'Trimestre en cours'
+	},
+	form: {
+		submit: 'Soumettre'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/fr_FR.ts

@@ -21,7 +21,8 @@ const fr_FR: LangProps = {
 		secondaryText: 'Annuler'
 	},
 	input: {
-		pleaseInput: 'Veuillez renseigner'
+		pleaseInput: 'Veuillez renseigner',
+		pleaseSelect: 'Veuillez sélectionner'
 	},
 	modal: {
 		title: 'Titre',
@@ -90,6 +91,9 @@ const fr_FR: LangProps = {
 		currentWeekText: 'Semaine en cours',
 		currentMonthText: 'Mois en cours',
 		currentQuarterText: 'Trimestre en cours'
+	},
+	form: {
+		submit: 'Soumettre'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/ga_IE.ts

@@ -21,7 +21,8 @@ const ga_IE: LangProps = {
 		secondaryText: 'Cealaigh'
 	},
 	input: {
-		pleaseInput: 'Cuir isteach le do thoil'
+		pleaseInput: 'Cuir isteach le do thoil',
+		pleaseSelect: 'Roghnaigh le do thoil'
 	},
 	modal: {
 		title: 'Teideal',
@@ -90,6 +91,9 @@ const ga_IE: LangProps = {
 		currentWeekText: 'Seachtain reatha',
 		currentMonthText: 'Mí reatha',
 		currentQuarterText: 'Ráithe reatha'
+	},
+	form: {
+		submit: 'Cuir isteach'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/gl_ES.ts

@@ -21,7 +21,8 @@ const gl_ES: LangProps = {
 		secondaryText: 'Cancelar'
 	},
 	input: {
-		pleaseInput: 'Por favor introduzca'
+		pleaseInput: 'Por favor introduzca',
+		pleaseSelect: 'Por favor seleccione'
 	},
 	modal: {
 		title: 'Título',
@@ -77,6 +78,9 @@ const gl_ES: LangProps = {
 		currentWeekText: 'Semana actual',
 		currentMonthText: 'Este mes',
 		currentQuarterText: 'Este cuarto'
+	},
+	form: {
+		submit: 'Enviar'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/he_IL.ts

@@ -21,7 +21,8 @@ const he_IL: LangProps = {
 		secondaryText: 'בטל'
 	},
 	input: {
-		pleaseInput: 'אנא הזן'
+		pleaseInput: 'אנא הזן',
+		pleaseSelect: 'אנא בחר'
 	},
 	modal: {
 		title: 'כותרת',
@@ -77,6 +78,9 @@ const he_IL: LangProps = {
 		currentWeekText: 'שבוע נוכחי',
 		currentMonthText: 'חודש נוכחי',
 		currentQuarterText: 'רבעון נוכחי'
+	},
+	form: {
+		submit: 'שלח'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/hi_IN.ts

@@ -21,7 +21,8 @@ const hi_IN: LangProps = {
 		secondaryText: 'रद्द करें'
 	},
 	input: {
-		pleaseInput: 'कृपया इनपुट करें'
+		pleaseInput: 'कृपया इनपुट करें',
+		pleaseSelect: 'कृपया चुनें'
 	},
 	modal: {
 		title: 'शीर्षक',
@@ -77,6 +78,9 @@ const hi_IN: LangProps = {
 		currentWeekText: 'वर्तमान सप्ताह',
 		currentMonthText: 'वर्तमान महीना',
 		currentQuarterText: 'वर्तमान तिमाही'
+	},
+	form: {
+		submit: 'जमा करें'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/hr_HR.ts

@@ -21,7 +21,8 @@ const hr_HR: LangProps = {
 		secondaryText: 'Otkaži'
 	},
 	input: {
-		pleaseInput: 'Molimo unesite'
+		pleaseInput: 'Molimo unesite',
+		pleaseSelect: 'Molimo odaberite'
 	},
 	modal: {
 		title: 'Naslov',
@@ -90,6 +91,9 @@ const hr_HR: LangProps = {
 		currentWeekText: 'Ovaj tjedan',
 		currentMonthText: 'Ovaj mjesec',
 		currentQuarterText: 'Ovo tromjesečje'
+	},
+	form: {
+		submit: 'Pošalji'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/hu_HU.ts

@@ -21,7 +21,8 @@ const hu_HU: LangProps = {
 		secondaryText: 'Mégsem'
 	},
 	input: {
-		pleaseInput: 'Kérem írja be'
+		pleaseInput: 'Kérem írja be',
+		pleaseSelect: 'Kérjük válasszon'
 	},
 	modal: {
 		title: 'Cím',
@@ -90,6 +91,9 @@ const hu_HU: LangProps = {
 		currentWeekText: 'Ezen a héten',
 		currentMonthText: 'Ebben a hónapban',
 		currentQuarterText: 'Ebben a negyedévben'
+	},
+	form: {
+		submit: 'Küldés'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/hy_AM.ts

@@ -21,7 +21,8 @@ const hy_AM: LangProps = {
 		secondaryText: 'Չեղարկել'
 	},
 	input: {
-		pleaseInput: 'Խնդրում եմ մուտքագրել'
+		pleaseInput: 'Խնդրում եմ մուտքագրել',
+		pleaseSelect: 'Խնդրում ենք ընտրել'
 	},
 	modal: {
 		title: 'Վերնագիր',
@@ -90,6 +91,9 @@ const hy_AM: LangProps = {
 		currentWeekText: 'Այս շաբաթ',
 		currentMonthText: 'Այս ամսվա մեջ',
 		currentQuarterText: 'Այս եռամսյա մեջ'
+	},
+	form: {
+		submit: 'Ուղարկել'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/id_ID.ts

@@ -21,7 +21,8 @@ const id_ID: LangProps = {
 		secondaryText: 'Batal'
 	},
 	input: {
-		pleaseInput: 'Silakan masukkan'
+		pleaseInput: 'Silakan masukkan',
+		pleaseSelect: 'Silakan pilih'
 	},
 	modal: {
 		title: 'Judul',
@@ -90,6 +91,9 @@ const id_ID: LangProps = {
 		currentWeekText: 'Minggu Ini',
 		currentMonthText: 'Bulan Ini',
 		currentQuarterText: 'Kuartal Ini'
+	},
+	form: {
+		submit: 'Kirim'
 	}
 };
 

+ 4 - 0
packages/stdf/src/lib/lang/index.ts

@@ -87,6 +87,7 @@ export type LangProps = {
 	};
 	input: {
 		pleaseInput: string;
+		pleaseSelect: string;
 	};
 	modal: {
 		title: string;
@@ -143,4 +144,7 @@ export type LangProps = {
 		currentMonthText: string;
 		currentQuarterText: string;
 	};
+	form: {
+		submit: string;
+	};
 };

+ 5 - 1
packages/stdf/src/lib/lang/is_IS.ts

@@ -21,7 +21,8 @@ const is_IS: LangProps = {
 		secondaryText: 'Hætta við'
 	},
 	input: {
-		pleaseInput: 'Vinsamlegast sláðu inn'
+		pleaseInput: 'Vinsamlegast sláðu inn',
+		pleaseSelect: 'Vinsamlegast veljið'
 	},
 	modal: {
 		title: 'Titill',
@@ -77,6 +78,9 @@ const is_IS: LangProps = {
 		currentWeekText: 'Þessi vika',
 		currentMonthText: 'Þessi mánuður',
 		currentQuarterText: 'Þessi fjórðungur'
+	},
+	form: {
+		submit: 'Senda'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/it_IT.ts

@@ -21,7 +21,8 @@ const it_IT: LangProps = {
 		secondaryText: 'Annulla'
 	},
 	input: {
-		pleaseInput: 'Si prega di inserire'
+		pleaseInput: 'Si prega di inserire',
+		pleaseSelect: 'Si prega di selezionare'
 	},
 	modal: {
 		title: 'Titolo',
@@ -90,6 +91,9 @@ const it_IT: LangProps = {
 		currentWeekText: 'Questa settimana',
 		currentMonthText: 'Questo mese',
 		currentQuarterText: 'Questo trimestre'
+	},
+	form: {
+		submit: 'Invia'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/ja_JP.ts

@@ -21,7 +21,8 @@ const ja_JP: LangProps = {
 		secondaryText: 'キャンセル'
 	},
 	input: {
-		pleaseInput: '入力してください'
+		pleaseInput: '入力してください',
+		pleaseSelect: '選択してください'
 	},
 	modal: {
 		title: 'タイトル',
@@ -77,6 +78,9 @@ const ja_JP: LangProps = {
 		currentWeekText: '今週',
 		currentMonthText: '今月',
 		currentQuarterText: '今四半期'
+	},
+	form: {
+		submit: '送信'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/ka_GE.ts

@@ -21,7 +21,8 @@ const ka_GE: LangProps = {
 		secondaryText: 'გაუქმება'
 	},
 	input: {
-		pleaseInput: 'შეიყვანეთ'
+		pleaseInput: 'შეიყვანეთ',
+		pleaseSelect: 'გთხოვთ აირჩიოთ'
 	},
 	modal: {
 		title: 'სათაური',
@@ -91,6 +92,9 @@ const ka_GE: LangProps = {
 		currentWeekText: 'ამ კვირაში',
 		currentMonthText: 'ამ თვეში',
 		currentQuarterText: 'ამ კვარტალში'
+	},
+	form: {
+		submit: 'გაგზავნა'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/kk_KZ.ts

@@ -21,7 +21,8 @@ const kk_KZ: LangProps = {
 		secondaryText: 'Болдырмау'
 	},
 	input: {
-		pleaseInput: 'Құпия сөзді енгізіңіз'
+		pleaseInput: 'Құпия сөзді енгізіңіз',
+		pleaseSelect: 'Таңдаңыз'
 	},
 	modal: {
 		title: 'Тақырып',
@@ -77,6 +78,9 @@ const kk_KZ: LangProps = {
 		currentWeekText: 'Бұл апта',
 		currentMonthText: 'Бұл ай',
 		currentQuarterText: 'Бұл тоқсаны'
+	},
+	form: {
+		submit: 'Жіберу'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/km_KH.ts

@@ -21,7 +21,8 @@ const km_KH: LangProps = {
 		secondaryText: 'បោះបង់'
 	},
 	input: {
-		pleaseInput: 'សូមបំពេញ'
+		pleaseInput: 'សូមបំពេញ',
+		pleaseSelect: 'សូមជ្រើសរើស'
 	},
 	modal: {
 		title: 'ចំណងជើង',
@@ -77,6 +78,9 @@ const km_KH: LangProps = {
 		currentWeekText: 'សប្តាហ៍នេះ',
 		currentMonthText: 'ខែនេះ',
 		currentQuarterText: 'ត្រីមាសនេះ'
+	},
+	form: {
+		submit: 'ផ្ញើ'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/kmr_IQ.ts

@@ -21,7 +21,8 @@ const kmr_IQ: LangProps = {
 		secondaryText: 'Betalke'
 	},
 	input: {
-		pleaseInput: 'Ji kerema xwe bixwîne'
+		pleaseInput: 'Ji kerema xwe bixwîne',
+		pleaseSelect: 'Hilbijêre'
 	},
 	modal: {
 		title: 'Nav',
@@ -90,6 +91,9 @@ const kmr_IQ: LangProps = {
 		currentWeekText: 'Ji bo herî dawî ji bo asta',
 		currentMonthText: 'Ji bo herî dawî ji bo asta',
 		currentQuarterText: 'Ji bo herî dawî ji bo asta'
+	},
+	form: {
+		submit: 'Bişîne'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/kn_IN.ts

@@ -21,7 +21,8 @@ const kn_IN: LangProps = {
 		secondaryText: 'ರದ್ದುಪಡಿಸಿ'
 	},
 	input: {
-		pleaseInput: 'ದಯವಿಟ್ಟು ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ನಮೂದಿಸಿ'
+		pleaseInput: 'ದಯವಿಟ್ಟು ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ನಮೂದಿಸಿ',
+		pleaseSelect: 'ದಯವಿಟ್ಟು ಆಯ್ಕೆಮಾಡಿ'
 	},
 	modal: {
 		title: 'ಶೀರ್ಷಿಕೆ',
@@ -90,6 +91,9 @@ const kn_IN: LangProps = {
 		currentWeekText: 'ಈ ವಾರ',
 		currentMonthText: 'ಈ ತಿಂಗಳು',
 		currentQuarterText: 'ಈ ತ್ರೈಮಾಸಿಕ'
+	},
+	form: {
+		submit: 'ಸಲ್ಲಿಸಿ'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/ko_KR.ts

@@ -21,7 +21,8 @@ const ko_KR: LangProps = {
 		secondaryText: '취소'
 	},
 	input: {
-		pleaseInput: '비밀번호를 입력해주세요'
+		pleaseInput: '비밀번호를 입력해주세요',
+		pleaseSelect: '선택해 주세요'
 	},
 	modal: {
 		title: '제목',
@@ -77,6 +78,9 @@ const ko_KR: LangProps = {
 		currentWeekText: '이번 주',
 		currentMonthText: '이번 달',
 		currentQuarterText: '이번 분기'
+	},
+	form: {
+		submit: '제출'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/lt_LT.ts

@@ -21,7 +21,8 @@ const lt_LT: LangProps = {
 		secondaryText: 'Atšaukti'
 	},
 	input: {
-		pleaseInput: 'Įveskite slaptažodį'
+		pleaseInput: 'Įveskite slaptažodį',
+		pleaseSelect: 'Prašome pasirinkti'
 	},
 	modal: {
 		title: 'Pavadinimas',
@@ -90,6 +91,9 @@ const lt_LT: LangProps = {
 		currentWeekText: 'Ši savaitė',
 		currentMonthText: 'Šis mėnuo',
 		currentQuarterText: 'Šis ketvirtis'
+	},
+	form: {
+		submit: 'Pateikti'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/lv_LV.ts

@@ -21,7 +21,8 @@ const lv_LV: LangProps = {
 		secondaryText: 'Atcelt'
 	},
 	input: {
-		pleaseInput: 'Lūdzu, ievadiet paroli'
+		pleaseInput: 'Lūdzu, ievadiet paroli',
+		pleaseSelect: 'Lūdzu izvēlieties'
 	},
 	modal: {
 		title: 'Nosaukums',
@@ -90,6 +91,9 @@ const lv_LV: LangProps = {
 		currentWeekText: 'Šonedēļ',
 		currentMonthText: 'Šomēnes',
 		currentQuarterText: 'Šajā ceturksnī'
+	},
+	form: {
+		submit: 'Iesniegt'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/mk_MK.ts

@@ -21,7 +21,8 @@ const mk_MK: LangProps = {
 		secondaryText: 'Откажи'
 	},
 	input: {
-		pleaseInput: 'Внесете лозинка'
+		pleaseInput: 'Внесете лозинка',
+		pleaseSelect: 'Ве молиме изберете'
 	},
 	modal: {
 		title: 'Наслов',
@@ -90,6 +91,9 @@ const mk_MK: LangProps = {
 		currentWeekText: 'Оваа недела',
 		currentMonthText: 'Овој месец',
 		currentQuarterText: 'Оваа тромесечје'
+	},
+	form: {
+		submit: 'Испрати'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/ml_IN.ts

@@ -21,7 +21,8 @@ const ml_IN: LangProps = {
 		secondaryText: 'റദ്ദാക്കുക'
 	},
 	input: {
-		pleaseInput: 'പാസ്സ്വേഡ് നൽകുക'
+		pleaseInput: 'പാസ്സ്വേഡ് നൽകുക',
+		pleaseSelect: 'ദയവായി തിരഞ്ഞെടുക്കുക'
 	},
 	modal: {
 		title: 'ശീർഷകം',
@@ -91,6 +92,9 @@ const ml_IN: LangProps = {
 		currentWeekText: 'ഈ ആഴ്ച',
 		currentMonthText: 'ഈ മാസം',
 		currentQuarterText: 'ഈ ക്വാർട്ടർ'
+	},
+	form: {
+		submit: 'സമർപ്പിക്കുക'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/mn_MN.ts

@@ -21,7 +21,8 @@ const mn_MN: LangProps = {
 		secondaryText: 'Цуцлах'
 	},
 	input: {
-		pleaseInput: 'Нууц үгээ оруулна уу'
+		pleaseInput: 'Нууц үгээ оруулна уу',
+		pleaseSelect: 'Сонгоно уу'
 	},
 	modal: {
 		title: 'Гарчиг',
@@ -78,6 +79,9 @@ const mn_MN: LangProps = {
 		currentWeekText: 'Энэ долоо хоног',
 		currentMonthText: 'Энэ сар',
 		currentQuarterText: 'Энэ улирал'
+	},
+	form: {
+		submit: 'Илгээх'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/ms_MY.ts

@@ -21,7 +21,8 @@ const ms_MY: LangProps = {
 		secondaryText: 'Batal'
 	},
 	input: {
-		pleaseInput: 'Sila masukkan kata laluan'
+		pleaseInput: 'Sila masukkan kata laluan',
+		pleaseSelect: 'Sila pilih'
 	},
 	modal: {
 		title: 'Tajuk',
@@ -78,6 +79,9 @@ const ms_MY: LangProps = {
 		currentWeekText: 'Minggu ini',
 		currentMonthText: 'Bulan ini',
 		currentQuarterText: 'Suku Tahun Ini'
+	},
+	form: {
+		submit: 'Hantar'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/nb_NO.ts

@@ -21,7 +21,8 @@ const nb_NO: LangProps = {
 		secondaryText: 'Avbryt'
 	},
 	input: {
-		pleaseInput: 'Vennligst skriv inn'
+		pleaseInput: 'Vennligst skriv inn',
+		pleaseSelect: 'Vennligst velg'
 	},
 	modal: {
 		title: 'Tittel',
@@ -77,6 +78,9 @@ const nb_NO: LangProps = {
 		currentWeekText: 'Denne uken',
 		currentMonthText: 'Denne måneden',
 		currentQuarterText: 'Dette kvartalet'
+	},
+	form: {
+		submit: 'Send'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/ne_NP.ts

@@ -21,7 +21,8 @@ const ne_NP: LangProps = {
 		secondaryText: 'रद्द गर्नुहोस्'
 	},
 	input: {
-		pleaseInput: 'कृपया टाइप गर्नुहोस्'
+		pleaseInput: 'कृपया टाइप गर्नुहोस्',
+		pleaseSelect: 'कृपया चयन गर्नुहोस्'
 	},
 	modal: {
 		title: 'शीर्षक',
@@ -77,6 +78,9 @@ const ne_NP: LangProps = {
 		currentWeekText: 'यो हप्ता',
 		currentMonthText: 'यो महिना',
 		currentQuarterText: 'यो तिमीहरूको तिमी'
+	},
+	form: {
+		submit: 'पेश गर्नुहोस्'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/nl_BE.ts

@@ -21,7 +21,8 @@ const nl_BE: LangProps = {
 		secondaryText: 'Annuleren'
 	},
 	input: {
-		pleaseInput: 'Voer in'
+		pleaseInput: 'Voer in',
+		pleaseSelect: 'Selecteer alsjeblieft'
 	},
 	modal: {
 		title: 'Titel',
@@ -90,6 +91,9 @@ const nl_BE: LangProps = {
 		currentWeekText: 'Deze week',
 		currentMonthText: 'Deze maand',
 		currentQuarterText: 'Dit kwartaal'
+	},
+	form: {
+		submit: 'Verzenden'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/nl_NL.ts

@@ -21,7 +21,8 @@ const nl_NL: LangProps = {
 		secondaryText: 'Annuleren'
 	},
 	input: {
-		pleaseInput: 'Voer in'
+		pleaseInput: 'Voer in',
+		pleaseSelect: 'Selecteer alsjeblieft'
 	},
 	modal: {
 		title: 'Titel',
@@ -90,6 +91,9 @@ const nl_NL: LangProps = {
 		currentWeekText: 'Deze week',
 		currentMonthText: 'Deze maand',
 		currentQuarterText: 'Dit kwartaal'
+	},
+	form: {
+		submit: 'Verzenden'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/pl_PL.ts

@@ -21,7 +21,8 @@ const pl_PL: LangProps = {
 		secondaryText: 'Anuluj'
 	},
 	input: {
-		pleaseInput: 'Wprowadź'
+		pleaseInput: 'Wprowadź',
+		pleaseSelect: 'Proszę wybierz'
 	},
 	modal: {
 		title: 'Tytuł',
@@ -90,6 +91,9 @@ const pl_PL: LangProps = {
 		currentWeekText: 'Bieżący tydzień',
 		currentMonthText: 'Bieżący miesiąc',
 		currentQuarterText: 'Bieżący kwartał'
+	},
+	form: {
+		submit: 'Wyślij'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/pt_BR.ts

@@ -21,7 +21,8 @@ const pt_BR: LangProps = {
 		secondaryText: 'Cancelar'
 	},
 	input: {
-		pleaseInput: 'Por favor, insira'
+		pleaseInput: 'Por favor, insira',
+		pleaseSelect: 'Por favor selecione'
 	},
 	modal: {
 		title: 'Título',
@@ -90,6 +91,9 @@ const pt_BR: LangProps = {
 		currentWeekText: 'Esta semana',
 		currentMonthText: 'Este mês',
 		currentQuarterText: 'Este trimestre'
+	},
+	form: {
+		submit: 'Enviar'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/pt_PT.ts

@@ -21,7 +21,8 @@ const pt_PT: LangProps = {
 		secondaryText: 'Cancelar'
 	},
 	input: {
-		pleaseInput: 'Por favor, insira'
+		pleaseInput: 'Por favor, insira',
+		pleaseSelect: 'Por favor seleccione'
 	},
 	modal: {
 		title: 'Título',
@@ -90,6 +91,9 @@ const pt_PT: LangProps = {
 		currentWeekText: 'Esta semana',
 		currentMonthText: 'Este mês',
 		currentQuarterText: 'Este trimestre'
+	},
+	form: {
+		submit: 'Enviar'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/ro_RO.ts

@@ -21,7 +21,8 @@ const ro_RO: LangProps = {
 		secondaryText: 'Anulează'
 	},
 	input: {
-		pleaseInput: 'Introduceți'
+		pleaseInput: 'Introduceți',
+		pleaseSelect: 'Vă rugăm selectați'
 	},
 	modal: {
 		title: 'Titlu',
@@ -90,6 +91,9 @@ const ro_RO: LangProps = {
 		currentWeekText: 'Săptămâna aceasta',
 		currentMonthText: 'Luna aceasta',
 		currentQuarterText: 'Acest trimestru'
+	},
+	form: {
+		submit: 'Trimite'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/ru_RU.ts

@@ -21,7 +21,8 @@ const ru_RU: LangProps = {
 		secondaryText: 'Отмена'
 	},
 	input: {
-		pleaseInput: 'Пожалуйста, введите'
+		pleaseInput: 'Пожалуйста, введите',
+		pleaseSelect: 'Пожалуйста выберите'
 	},
 	modal: {
 		title: 'Заголовок',
@@ -77,6 +78,9 @@ const ru_RU: LangProps = {
 		currentWeekText: 'Текущая неделя',
 		currentMonthText: 'Текущий месяц',
 		currentQuarterText: 'Текущий квартал'
+	},
+	form: {
+		submit: 'Отправить'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/si_LK.ts

@@ -21,7 +21,8 @@ const si_LK: LangProps = {
 		secondaryText: 'ඉවත් කරන්න'
 	},
 	input: {
-		pleaseInput: 'කරුණාකර ඇතුලත් කරන්න'
+		pleaseInput: 'කරුණාකර ඇතුලත් කරන්න',
+		pleaseSelect: 'කරුණාකර තෝරන්න'
 	},
 	modal: {
 		title: 'මාතෘකාව',
@@ -90,6 +91,9 @@ const si_LK: LangProps = {
 		currentWeekText: 'මෙම සතිය',
 		currentMonthText: 'මෙම මාසය',
 		currentQuarterText: 'මෙම කාර්තුව'
+	},
+	form: {
+		submit: 'ඉදිරිපත් කරන්න'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/sk_SK.ts

@@ -21,7 +21,8 @@ const sk_SK: LangProps = {
 		secondaryText: 'Cancel'
 	},
 	input: {
-		pleaseInput: 'Prosím zadajte'
+		pleaseInput: 'Prosím zadajte',
+		pleaseSelect: 'Prosím vyberte'
 	},
 	modal: {
 		title: 'Titulok',
@@ -77,6 +78,9 @@ const sk_SK: LangProps = {
 		currentWeekText: 'Tento týždeň',
 		currentMonthText: 'Tento mesiac',
 		currentQuarterText: 'Tento štvrťrok'
+	},
+	form: {
+		submit: 'Odoslať'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/sl_SI.ts

@@ -21,7 +21,8 @@ const sl_SI: LangProps = {
 		secondaryText: 'Prekliči'
 	},
 	input: {
-		pleaseInput: 'Prosim vnesite'
+		pleaseInput: 'Prosim vnesite',
+		pleaseSelect: 'Prosim izberite'
 	},
 	modal: {
 		title: 'Naslov',
@@ -90,6 +91,9 @@ const sl_SI: LangProps = {
 		currentWeekText: 'Ta teden',
 		currentMonthText: 'Ta mesec',
 		currentQuarterText: 'To četrtletje'
+	},
+	form: {
+		submit: 'Pošlji'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/sr_RS.ts

@@ -21,7 +21,8 @@ const sr_RS: LangProps = {
 		secondaryText: 'Otkaži'
 	},
 	input: {
-		pleaseInput: 'Molimo unesite'
+		pleaseInput: 'Molimo unesite',
+		pleaseSelect: 'Молимо изаберите'
 	},
 	modal: {
 		title: 'Naslov',
@@ -77,6 +78,9 @@ const sr_RS: LangProps = {
 		currentWeekText: 'Ovaj tjedan',
 		currentMonthText: 'Ovaj mjesec',
 		currentQuarterText: 'Ovaj kvartal'
+	},
+	form: {
+		submit: 'Пошаљи'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/sv_SE.ts

@@ -21,7 +21,8 @@ const sv_SE: LangProps = {
 		secondaryText: 'Avbryt'
 	},
 	input: {
-		pleaseInput: 'Vänligen fyll i'
+		pleaseInput: 'Vänligen fyll i',
+		pleaseSelect: 'Vänligen välj'
 	},
 	modal: {
 		title: 'Titel',
@@ -90,6 +91,9 @@ const sv_SE: LangProps = {
 		currentWeekText: 'Denna vecka',
 		currentMonthText: 'Denna månad',
 		currentQuarterText: 'Detta kvartal'
+	},
+	form: {
+		submit: 'Skicka'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/ta_IN.ts

@@ -21,7 +21,8 @@ const ta_IN: LangProps = {
 		secondaryText: 'ரத்துசெய்'
 	},
 	input: {
-		pleaseInput: 'தயவு செய்து உள்ளிடவும்'
+		pleaseInput: 'தயவு செய்து உள்ளிடவும்',
+		pleaseSelect: 'தயவுசெய்து தேர்ந்தெடுக்கவும்'
 	},
 	modal: {
 		title: 'தலைப்பு',
@@ -90,6 +91,9 @@ const ta_IN: LangProps = {
 		currentWeekText: 'இந்த வாரம்',
 		currentMonthText: 'இந்த மாதம்',
 		currentQuarterText: 'இந்த காலாண்டு'
+	},
+	form: {
+		submit: 'சமர்ப்பிக்கவும்'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/th_TH.ts

@@ -21,7 +21,8 @@ const th_TH: LangProps = {
 		secondaryText: 'ยกเลิก'
 	},
 	input: {
-		pleaseInput: 'กรุณากรอกข้อมูล'
+		pleaseInput: 'กรุณากรอกข้อมูล',
+		pleaseSelect: 'กรุณาเลือก'
 	},
 	modal: {
 		title: 'กรุณายืนยัน',
@@ -77,6 +78,9 @@ const th_TH: LangProps = {
 		currentWeekText: 'สัปดาห์นี้',
 		currentMonthText: 'เดือนนี้',
 		currentQuarterText: 'ไตรมาสนี้'
+	},
+	form: {
+		submit: 'ส่ง'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/tk_TK.ts

@@ -21,7 +21,8 @@ const tk_TK: LangProps = {
 		secondaryText: 'Gurnama'
 	},
 	input: {
-		pleaseInput: 'Eçow giriziň'
+		pleaseInput: 'Eçow giriziň',
+		pleaseSelect: 'Saýlaň'
 	},
 	modal: {
 		title: 'Tassyklaň',
@@ -77,6 +78,9 @@ const tk_TK: LangProps = {
 		currentWeekText: 'Bu hepde',
 		currentMonthText: 'Bu aý',
 		currentQuarterText: 'Bu çärýek'
+	},
+	form: {
+		submit: 'Ugrat'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/tr_TR.ts

@@ -21,7 +21,8 @@ const tr_TR: LangProps = {
 		secondaryText: 'İptal'
 	},
 	input: {
-		pleaseInput: 'Lütfen giriş yapınız'
+		pleaseInput: 'Lütfen giriş yapınız',
+		pleaseSelect: 'Lütfen seçin'
 	},
 	modal: {
 		title: 'Onay',
@@ -77,6 +78,9 @@ const tr_TR: LangProps = {
 		currentWeekText: 'Bu hafta',
 		currentMonthText: 'Bu ay',
 		currentQuarterText: 'Bu çeyrek'
+	},
+	form: {
+		submit: 'Gönder'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/uk_UA.ts

@@ -21,7 +21,8 @@ const uk_UA: LangProps = {
 		secondaryText: 'Скасувати'
 	},
 	input: {
-		pleaseInput: 'Будь ласка, введіть'
+		pleaseInput: 'Будь ласка, введіть',
+		pleaseSelect: 'Будь ласка виберіть'
 	},
 	modal: {
 		title: 'Підтвердження',
@@ -90,6 +91,9 @@ const uk_UA: LangProps = {
 		currentWeekText: 'Поточний тиждень',
 		currentMonthText: 'Поточний місяць',
 		currentQuarterText: 'Поточний квартал'
+	},
+	form: {
+		submit: 'Надіслати'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/ur_PK.ts

@@ -21,7 +21,8 @@ const ur_PK: LangProps = {
 		secondaryText: 'منسوخ'
 	},
 	input: {
-		pleaseInput: 'براہ کرم انپٹ کریں'
+		pleaseInput: 'براہ کرم انپٹ کریں',
+		pleaseSelect: 'براہ کرم منتخب کریں'
 	},
 	modal: {
 		title: 'تصدیق کریں',
@@ -77,6 +78,9 @@ const ur_PK: LangProps = {
 		currentWeekText: 'اس ہفتے',
 		currentMonthText: 'اس مہینہ',
 		currentQuarterText: 'اس ترکیب'
+	},
+	form: {
+		submit: 'جمع کریں'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/vi_VN.ts

@@ -21,7 +21,8 @@ const vi_VN: LangProps = {
 		secondaryText: 'Hủy'
 	},
 	input: {
-		pleaseInput: 'Vui lòng nhập'
+		pleaseInput: 'Vui lòng nhập',
+		pleaseSelect: 'Vui lòng chọn'
 	},
 	modal: {
 		title: 'Xác nhận',
@@ -90,6 +91,9 @@ const vi_VN: LangProps = {
 		currentWeekText: 'Tuần này',
 		currentMonthText: 'Tháng này',
 		currentQuarterText: 'Quý này'
+	},
+	form: {
+		submit: 'Gửi'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/zh_CN.ts

@@ -21,7 +21,8 @@ const zh_CN: LangProps = {
 		secondaryText: '取消'
 	},
 	input: {
-		pleaseInput: '请输入'
+		pleaseInput: '请输入',
+		pleaseSelect: '请选择'
 	},
 	modal: {
 		title: '标题',
@@ -77,6 +78,9 @@ const zh_CN: LangProps = {
 		currentWeekText: '本周',
 		currentMonthText: '本月',
 		currentQuarterText: '本季度'
+	},
+	form: {
+		submit: '提交'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/zh_HK.ts

@@ -21,7 +21,8 @@ const zh_HK: LangProps = {
 		secondaryText: '取消'
 	},
 	input: {
-		pleaseInput: '請輸入'
+		pleaseInput: '請輸入',
+		pleaseSelect: '請選擇'
 	},
 	modal: {
 		title: '標題',
@@ -77,6 +78,9 @@ const zh_HK: LangProps = {
 		currentWeekText: '本週',
 		currentMonthText: '本月',
 		currentQuarterText: '本季度'
+	},
+	form: {
+		submit: '提交'
 	}
 };
 

+ 5 - 1
packages/stdf/src/lib/lang/zh_TW.ts

@@ -21,7 +21,8 @@ const zh_TW: LangProps = {
 		secondaryText: '取消'
 	},
 	input: {
-		pleaseInput: '請輸入'
+		pleaseInput: '請輸入',
+		pleaseSelect: '請選擇'
 	},
 	modal: {
 		title: '標題',
@@ -77,6 +78,9 @@ const zh_TW: LangProps = {
 		currentWeekText: '本週',
 		currentMonthText: '本月',
 		currentQuarterText: '本季度'
+	},
+	form: {
+		submit: '提交'
 	}
 };
 

+ 154 - 3
packages/stdf/src/lib/types/index.ts

@@ -12,7 +12,7 @@ export type ActionSheetProps = {
 	visible?: boolean;
 	title?: string;
 	titleAlign?: 'left' | 'center' | 'right';
-	actions?: ActionProps[];
+	actions: ActionProps[];
 	popup?: PopupProps;
 	showCancel?: boolean;
 	cancelText?: string;
@@ -312,6 +312,9 @@ export type InputProps = {
 	state?: 'theme' | 'success' | 'warning' | 'error' | 'info';
 	type?: 'text' | 'decimal' | 'email' | 'none' | 'numeric' | 'search' | 'tel' | 'url' | 'password' | 'number' | 'textarea';
 	inputmode?: 'text' | 'decimal' | 'email' | 'none' | 'numeric' | 'search' | 'tel' | 'url' | '';
+	readonly?: boolean;
+	select?: boolean;
+	required?: boolean;
 	maxlength?: number;
 	textareaMaxlength?: number;
 	rows?: number;
@@ -441,7 +444,7 @@ export type NumKeyboardProps = {
 	keyClass?: string;
 	doneClass?: string;
 	popup?: PopupProps;
-	onclick?: (key: string) => void;
+	onclick?: (key: '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '.' | 'delete' | 'close' | 'done') => void;
 	onopen?: (height: number) => void;
 	onclose?: () => void;
 };
@@ -482,7 +485,7 @@ export type PickerDatasProps = {
 };
 export type PickerProps = {
 	visible?: boolean;
-	datas?: PickerDatasProps[] | PickerDataChildProps[];
+	datas: PickerDatasProps[] | PickerDataChildProps[];
 	autoScrollToLast?: boolean;
 	cancelText?: string;
 	confirmText?: string;
@@ -858,6 +861,154 @@ export type ToastProps = {
 	onclose?: () => void;
 };
 
+export type FormInputValue = string;
+export type FormTimePickerValue = { timeStr?: string; timeObj?: TimePickerObjProps };
+export type FormActionSheetValue = { action?: ActionProps; index?: number };
+export type FormCalendarValue = { dates?: string[] };
+export type FormNumKeyboardValue = string;
+export type FormPickerValue = { items?: { [key: string]: string }[]; indexs?: number[] };
+export type FormCheckboxValue = string[];
+export type FormRadioValue = string;
+export type FormSliderValue = { value?: number; valueRange?: [number, number] };
+export type FormSwitchValue = boolean;
+export type FormStepperValue = number;
+export type FormInputProps = {
+	type?: 'input';
+	name: string;
+	label: string;
+	initValue?: string;
+	required?: boolean;
+	input?: InputProps;
+};
+export type FormTimePickerProps = {
+	type?: 'timePicker';
+	name: string;
+	label: string;
+	initValue?: string;
+	required?: boolean;
+	timePicker?: TimePickerProps;
+	input?: InputProps;
+};
+export type FormActionSheetProps = {
+	type?: 'actionSheet';
+	name: string;
+	label: string;
+	initValue?: string;
+	required?: boolean;
+	actionSheet: ActionSheetProps;
+	input?: InputProps;
+};
+export type FormCalendarProps = {
+	type?: 'calendar';
+	name: string;
+	label: string;
+	initValue?: string;
+	required?: boolean;
+	calendar?: CalendarProps;
+	input?: InputProps;
+};
+export type FormNumKeyboardProps = {
+	type?: 'numKeyboard';
+	name: string;
+	label: string;
+	initValue?: string;
+	required?: boolean;
+	numKeyboard?: NumKeyboardProps;
+	input?: InputProps;
+};
+export type FormPickerProps = {
+	type?: 'picker';
+	name: string;
+	label: string;
+	initValue?: string;
+	linkageSeparator?: string;
+	required?: boolean;
+	picker?: PickerProps;
+	input?: InputProps;
+};
+export type FormCheckboxProps = {
+	type?: 'checkbox';
+	name: string;
+	label: string;
+	initValue?: string[];
+	required?: boolean;
+	checkbox?: CheckboxProps;
+};
+export type FormRadioProps = {
+	type?: 'radio';
+	name: string;
+	label: string;
+	initValue?: string;
+	required?: boolean;
+	radio?: RadioProps;
+};
+export type FormSliderProps = {
+	type?: 'slider';
+	name: string;
+	label: string;
+	initValue?: number | number[];
+	required?: boolean;
+	slider?: SliderProps;
+};
+export type FormSwitchProps = {
+	type?: 'switch';
+	name: string;
+	label: string;
+	initValue?: boolean;
+	required?: boolean;
+	switch?: SwitchProps;
+};
+export type FormStepperProps = {
+	type?: 'stepper';
+	name: string;
+	label: string;
+	initValue?: number;
+	required?: boolean;
+	stepper?: StepperProps;
+};
+export type FormItemProps =
+	| FormInputProps
+	| FormTimePickerProps
+	| FormActionSheetProps
+	| FormCalendarProps
+	| FormNumKeyboardProps
+	| FormPickerProps
+	| FormCheckboxProps
+	| FormRadioProps
+	| FormSliderProps
+	| FormSwitchProps
+	| FormStepperProps;
+export type FormValueProps =
+	| FormInputValue
+	| FormTimePickerValue
+	| FormActionSheetValue
+	| FormCalendarValue
+	| FormNumKeyboardValue
+	| FormPickerValue
+	| FormCheckboxValue
+	| FormRadioValue
+	| FormSliderValue
+	| FormSwitchValue
+	| FormStepperValue;
+export type FormProps = {
+	form: FormItemProps[];
+	submitText?: string;
+	submitButton?: ButtonProps;
+	resetText?: string | null;
+	resetButton?: ButtonProps;
+	submitChildren?: Snippet;
+	resetChildren?: Snippet;
+	space?: '0' | '1' | '2' | '4' | '6' | '8';
+	card?: boolean;
+	mx?: '2' | '3' | '4' | '6' | '8';
+	px?: '0' | '1' | '2' | '4' | '6';
+	radius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl';
+	shadow?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
+	onchange?: (data: Record<string, FormValueProps>) => void;
+	onsubmit?: (data: Record<string, FormValueProps>) => void;
+	onreset?: () => void;
+};
+
 export type SvelteEasingProps =
 	| 'backIn'
 	| 'backInOut'

+ 109 - 0
packages/stdf/src/routes/form/en_US/+page.svelte

@@ -0,0 +1,109 @@
+<script lang="ts">
+	import { Divider, Form, Toast } from '$lib/index.js';
+
+	import type { FormItemProps, FormValueProps } from '../../../lib/types/index.js';
+	import { someProvinceList, linkageData } from '../../picker/en_US/data_en.js';
+
+	// Form configuration
+	const formConfig: FormItemProps[] = [
+		{ type: 'input', name: 'username', label: 'Username', required: true },
+		{ type: 'numKeyboard', name: 'numKeyboard', label: 'Number Keyboard', input: { placeholder: 'Please enter numbers' } },
+		{ type: 'timePicker', name: 'time', label: 'Time', required: true },
+		{
+			type: 'actionSheet',
+			name: 'action',
+			label: 'Action',
+			actionSheet: { actions: [{ content: 'Add' }, { content: 'Edit' }, { content: 'Delete', style: 'danger', desc: 'Cannot be restored after deletion' }] }
+		},
+		{ type: 'calendar', name: 'calendar', label: 'Date Range', calendar: { mode: 'range' } },
+		{ type: 'picker', name: 'picker', label: 'State', picker: { datas: [{ data: someProvinceList }] } },
+		{ type: 'picker', name: 'pickerLinkage', label: 'Region', picker: { datas: linkageData, isLinkage: true } },
+		{
+			type: 'checkbox',
+			name: 'checkbox',
+			label: 'Select disabled heroes (multiple)',
+			initValue: [],
+			checkbox: {
+				data: [
+					{ label: 'Jugg', name: 'Juggernaut' },
+					{ label: 'SB', name: 'Spirit Breaker' },
+					{ label: 'KOTL', name: 'Keeper of the Light' },
+					{ label: 'Mag', name: 'Magnus' }
+				],
+				layout: 'h'
+			}
+		},
+		{
+			type: 'radio',
+			name: 'radio',
+			label: 'Select hero (single)',
+			required: true,
+			initValue: '',
+			radio: {
+				data: [
+					{ label: 'Jugg', name: 'Juggernaut' },
+					{ label: 'SB', name: 'Spirit Breaker' },
+					{ label: 'KOTL', name: 'Keeper of the Light' },
+					{ label: 'Mag', name: 'Magnus' }
+				],
+				layout: 'h'
+			}
+		},
+		{ type: 'slider', name: 'slider', label: 'Adjust Volume', slider: { isRange: true } },
+		{ type: 'switch', name: 'switch', label: 'Toggle Enable' },
+		{ type: 'stepper', name: 'stepper', label: 'Adjust Steps' }
+	];
+	let formValues = $state({});
+	const changeFunc = (data: Record<string, FormValueProps>) => {
+		formValues = data;
+	};
+	const resetFunc = () => {
+		formValues = {};
+	};
+	let submitToastVisible = $state(false);
+	let toastMessage = $derived(Object.keys(formValues).length > 0 ? 'Values available for submission' : 'No values, submission not allowed');
+	let toastType = $derived(Object.keys(formValues).length > 0 ? ('success' as const) : ('warning' as const));
+	const submitFunc = () => {
+		submitToastVisible = true;
+	};
+
+	const formCardConfig: FormItemProps[] = [
+		{ type: 'input', name: 'username', label: 'Username', required: true },
+		{ type: 'calendar', name: 'calendar', label: 'Date Range', calendar: { mode: 'range' } },
+		{ type: 'picker', name: 'pickerLinkage', label: 'Region', picker: { datas: linkageData, isLinkage: true } }
+	];
+
+	const formCardRadioConfig: FormItemProps[] = [
+		{ type: 'input', name: 'username', label: 'Username', required: true, input: { radius: 'full' } },
+		{ type: 'calendar', name: 'calendar', label: 'Date Range', calendar: { mode: 'range' }, input: { radius: 'full' } },
+		{ type: 'picker', name: 'pickerLinkage', label: 'Region', picker: { datas: linkageData, isLinkage: true }, input: { radius: 'full' } }
+	];
+
+	const formCardLineConfig: FormItemProps[] = [
+		{ type: 'input', name: 'username', label: 'Username', required: true, input: { inputStyle: 'line' } },
+		{ type: 'calendar', name: 'calendar', label: 'Date Range', calendar: { mode: 'range' }, input: { inputStyle: 'line' } },
+		{ type: 'picker', name: 'pickerLinkage', label: 'Region', picker: { datas: linkageData, isLinkage: true }, input: { inputStyle: 'line' } }
+	];
+</script>
+
+{#if Object.keys(formValues).length > 0}
+	<div class="z-100 sticky top-12 w-full break-all bg-white/50 p-1 text-left text-xs backdrop-blur-sm dark:bg-black/50">
+		<p>Form values display</p>
+		{JSON.stringify(formValues)}
+	</div>
+{/if}
+<Divider text="Basic usage, includes all supported form items" />
+<Form form={formConfig} onsubmit={submitFunc} onchange={changeFunc} resetText="Reset" onreset={resetFunc} />
+<Toast bind:visible={submitToastVisible} message={toastMessage} type={toastType} />
+
+<Divider text="Card Layout" />
+<Form form={formCardConfig} card />
+
+<Divider text="Increased Spacing" />
+<Form form={formCardConfig} space="4" />
+
+<Divider text="Increase the radius of cards, inputs and submit button" />
+<Form form={formCardRadioConfig} card radius="4xl" submitButton={{ radius: 'full' }} />
+
+<Divider text="Input Field Line Style" />
+<Form form={formCardLineConfig} />

+ 109 - 0
packages/stdf/src/routes/form/zh_CN/+page.svelte

@@ -0,0 +1,109 @@
+<script lang="ts">
+	import { Divider, Form, Toast } from '$lib/index.js';
+
+	import type { FormItemProps, FormValueProps } from '../../../lib/types/index.js';
+	import { someProvinceList, linkageData } from '../../picker/zh_CN/data.js';
+
+	// 表单配置
+	const formConfig: FormItemProps[] = [
+		{ type: 'input', name: 'username', label: '用户名', required: true },
+		{ type: 'numKeyboard', name: 'numKeyboard', label: '数字键盘', input: { placeholder: '请输入数字' } },
+		{ type: 'timePicker', name: 'time', label: '时间', required: true },
+		{
+			type: 'actionSheet',
+			name: 'action',
+			label: '操作方式',
+			actionSheet: { actions: [{ content: '新增' }, { content: '修改' }, { content: '删除', style: 'danger', desc: '删除后将无法恢复' }] }
+		},
+		{ type: 'calendar', name: 'calendar', label: '日期范围', calendar: { mode: 'range' } },
+		{ type: 'picker', name: 'picker', label: '省份', picker: { datas: [{ data: someProvinceList }] } },
+		{ type: 'picker', name: 'pickerLinkage', label: '地区', picker: { datas: linkageData, isLinkage: true } },
+		{
+			type: 'checkbox',
+			name: 'checkbox',
+			label: '请选择禁用英雄(多选)',
+			initValue: [],
+			checkbox: {
+				data: [
+					{ label: '主宰', name: '奶棒人' },
+					{ label: '白牛', name: '令狐冲' },
+					{ label: '光法', name: '光之守卫' },
+					{ label: '猛犸', name: '马格纳斯' }
+				],
+				layout: 'h'
+			}
+		},
+		{
+			type: 'radio',
+			name: 'radio',
+			label: '请选择英雄(单选)',
+			required: true,
+			initValue: '',
+			radio: {
+				data: [
+					{ label: '主宰', name: '奶棒人' },
+					{ label: '白牛', name: '令狐冲' },
+					{ label: '光法', name: '光之守卫' },
+					{ label: '猛犸', name: '马格纳斯' }
+				],
+				layout: 'h'
+			}
+		},
+		{ type: 'slider', name: 'slider', label: '请调整音量', slider: { isRange: true } },
+		{ type: 'switch', name: 'switch', label: '请选择是否开启' },
+		{ type: 'stepper', name: 'stepper', label: '请调整步数' }
+	];
+	let formValues = $state({});
+	const changeFunc = (data: Record<string, FormValueProps>) => {
+		formValues = data;
+	};
+	const resetFunc = () => {
+		formValues = {};
+	};
+	let submitToastVisible = $state(false);
+	let toastMessage = $derived(Object.keys(formValues).length > 0 ? '有值允许提交' : '没有值不允许提交');
+	let toastType = $derived(Object.keys(formValues).length > 0 ? ('success' as const) : ('warning' as const));
+	const submitFunc = () => {
+		submitToastVisible = true;
+	};
+
+	const formCardConfig: FormItemProps[] = [
+		{ type: 'input', name: 'username', label: '用户名', required: true },
+		{ type: 'calendar', name: 'calendar', label: '日期范围', calendar: { mode: 'range' } },
+		{ type: 'picker', name: 'pickerLinkage', label: '地区', picker: { datas: linkageData, isLinkage: true } }
+	];
+
+	const formCardRadioConfig: FormItemProps[] = [
+		{ type: 'input', name: 'username', label: '用户名', required: true, input: { radius: 'full' } },
+		{ type: 'calendar', name: 'calendar', label: '日期范围', calendar: { mode: 'range' }, input: { radius: 'full' } },
+		{ type: 'picker', name: 'pickerLinkage', label: '地区', picker: { datas: linkageData, isLinkage: true }, input: { radius: 'full' } }
+	];
+
+	const formCardLineConfig: FormItemProps[] = [
+		{ type: 'input', name: 'username', label: '用户名', required: true, input: { inputStyle: 'line' } },
+		{ type: 'calendar', name: 'calendar', label: '日期范围', calendar: { mode: 'range' }, input: { inputStyle: 'line' } },
+		{ type: 'picker', name: 'pickerLinkage', label: '地区', picker: { datas: linkageData, isLinkage: true }, input: { inputStyle: 'line' } }
+	];
+</script>
+
+{#if Object.keys(formValues).length > 0}
+	<div class="z-100 sticky top-12 w-full break-all bg-white/50 p-1 text-left text-xs backdrop-blur-sm dark:bg-black/50">
+		<p>这里展示表单的值</p>
+		{JSON.stringify(formValues)}
+	</div>
+{/if}
+<Divider text="基础用法,包含全部支持的表单项" />
+<Form form={formConfig} onsubmit={submitFunc} onchange={changeFunc} resetText="重置" onreset={resetFunc} />
+<Toast bind:visible={submitToastVisible} message={toastMessage} type={toastType} />
+
+<Divider text="卡片布局" />
+<Form form={formCardConfig} card />
+
+<Divider text="增加间距" />
+<Form form={formCardConfig} space="4" />
+
+<Divider text="增大卡片、输入框与提交按钮圆角" />
+<Form form={formCardRadioConfig} card radius="4xl" submitButton={{ radius: 'full' }} />
+
+<Divider text="输入框线性风格" />
+<Form form={formCardLineConfig} />