@stonecrop/aform 0.31.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/aform.js +3024 -2256
  2. package/dist/aform.js.map +1 -1
  3. package/dist/assets/index.css +1170 -1
  4. package/dist/src/components/AForm.vue.d.ts +20 -0
  5. package/dist/src/components/AForm.vue.d.ts.map +1 -0
  6. package/dist/src/components/AFormLoading.vue.d.ts +14 -0
  7. package/dist/src/components/AFormLoading.vue.d.ts.map +1 -0
  8. package/dist/src/components/base/CollapseButton.vue.d.ts +7 -0
  9. package/dist/src/components/base/CollapseButton.vue.d.ts.map +1 -0
  10. package/dist/src/components/base/ExpandButton.vue.d.ts +7 -0
  11. package/dist/src/components/base/ExpandButton.vue.d.ts.map +1 -0
  12. package/dist/src/components/form/ABadge.vue.d.ts +14 -0
  13. package/dist/src/components/form/ABadge.vue.d.ts.map +1 -0
  14. package/dist/src/components/form/ACheckbox.vue.d.ts +15 -0
  15. package/dist/src/components/form/ACheckbox.vue.d.ts.map +1 -0
  16. package/dist/src/components/form/ACurrencyInput.vue.d.ts +20 -0
  17. package/dist/src/components/form/ACurrencyInput.vue.d.ts.map +1 -0
  18. package/dist/src/components/form/ADate.vue.d.ts +14 -0
  19. package/dist/src/components/form/ADate.vue.d.ts.map +1 -0
  20. package/dist/src/components/form/ADatePicker.vue.d.ts +28 -0
  21. package/dist/src/components/form/ADatePicker.vue.d.ts.map +1 -0
  22. package/dist/src/components/form/ADateRange.vue.d.ts +18 -0
  23. package/dist/src/components/form/ADateRange.vue.d.ts.map +1 -0
  24. package/dist/src/components/form/ADateSelection.vue.d.ts +52 -0
  25. package/dist/src/components/form/ADateSelection.vue.d.ts.map +1 -0
  26. package/dist/src/components/form/ADateTime.vue.d.ts +17 -0
  27. package/dist/src/components/form/ADateTime.vue.d.ts.map +1 -0
  28. package/dist/src/components/form/ADateTimeInput.vue.d.ts +30 -0
  29. package/dist/src/components/form/ADateTimeInput.vue.d.ts.map +1 -0
  30. package/dist/src/components/form/ADropdown.vue.d.ts +20 -0
  31. package/dist/src/components/form/ADropdown.vue.d.ts.map +1 -0
  32. package/dist/src/components/form/ADuration.vue.d.ts +18 -0
  33. package/dist/src/components/form/ADuration.vue.d.ts.map +1 -0
  34. package/dist/src/components/form/AFieldset.vue.d.ts +28 -0
  35. package/dist/src/components/form/AFieldset.vue.d.ts.map +1 -0
  36. package/dist/src/components/form/AFileAttach.vue.d.ts +5 -0
  37. package/dist/src/components/form/AFileAttach.vue.d.ts.map +1 -0
  38. package/dist/src/components/form/AFormLink.vue.d.ts +40 -0
  39. package/dist/src/components/form/AFormLink.vue.d.ts.map +1 -0
  40. package/dist/src/components/form/ANumericInput.vue.d.ts +14 -0
  41. package/dist/src/components/form/ANumericInput.vue.d.ts.map +1 -0
  42. package/dist/src/components/form/AQuantityInput.vue.d.ts +20 -0
  43. package/dist/src/components/form/AQuantityInput.vue.d.ts.map +1 -0
  44. package/dist/src/components/form/ASegmentedControl.vue.d.ts +23 -0
  45. package/dist/src/components/form/ASegmentedControl.vue.d.ts.map +1 -0
  46. package/dist/src/components/form/ATextInput.vue.d.ts +14 -0
  47. package/dist/src/components/form/ATextInput.vue.d.ts.map +1 -0
  48. package/dist/src/components/form/ATextboxInput.vue.d.ts +21 -0
  49. package/dist/src/components/form/ATextboxInput.vue.d.ts.map +1 -0
  50. package/dist/src/components/utilities/Login.vue.d.ts +14 -0
  51. package/dist/src/components/utilities/Login.vue.d.ts.map +1 -0
  52. package/dist/{tsdoc-metadata.json → src/tsdoc-metadata.json} +1 -1
  53. package/package.json +35 -30
  54. package/dist/aform.d.ts +0 -441
  55. package/dist/aform.tsbuildinfo +0 -1
  56. package/dist/src/directives/mask.js +0 -107
  57. package/dist/src/index.js +0 -58
  58. package/dist/src/types/index.js +0 -0
  59. package/dist/src/utils/badge.js +0 -71
  60. package/dist/src/utils/columns.js +0 -33
  61. package/dist/src/utils/deserialize.js +0 -20
  62. package/src/components/AForm.vue +0 -314
  63. package/src/components/AFormLoading.vue +0 -76
  64. package/src/components/base/CollapseButton.vue +0 -36
  65. package/src/components/base/ExpandButton.vue +0 -34
  66. package/src/components/form/ABadge.vue +0 -135
  67. package/src/components/form/ACheckbox.vue +0 -62
  68. package/src/components/form/ACurrencyInput.vue +0 -357
  69. package/src/components/form/ADate.vue +0 -93
  70. package/src/components/form/ADatePicker.vue +0 -470
  71. package/src/components/form/ADateRange.vue +0 -133
  72. package/src/components/form/ADateSelection.vue +0 -174
  73. package/src/components/form/ADateTime.vue +0 -149
  74. package/src/components/form/ADateTimeInput.vue +0 -299
  75. package/src/components/form/ADropdown.vue +0 -222
  76. package/src/components/form/ADuration.vue +0 -124
  77. package/src/components/form/AFieldset.vue +0 -72
  78. package/src/components/form/AFileAttach.vue +0 -97
  79. package/src/components/form/AFormLink.vue +0 -368
  80. package/src/components/form/ANumericInput.vue +0 -32
  81. package/src/components/form/AQuantityInput.vue +0 -349
  82. package/src/components/form/ASegmentedControl.vue +0 -342
  83. package/src/components/form/ATextInput.vue +0 -40
  84. package/src/components/form/ATextboxInput.vue +0 -66
  85. package/src/components/utilities/Login.vue +0 -189
  86. package/src/directives/mask.ts +0 -122
  87. package/src/index.ts +0 -92
  88. package/src/shims-vue.d.ts +0 -5
  89. package/src/types/index.ts +0 -333
  90. package/src/utils/badge.ts +0 -94
  91. package/src/utils/columns.ts +0 -38
  92. package/src/utils/deserialize.ts +0 -20
@@ -1,40 +0,0 @@
1
- <template>
2
- <div class="aform_form-element">
3
- <template v-if="mode === 'display'">
4
- <span class="aform_display-value">{{ inputText ?? '' }}</span>
5
- <label class="aform_field-label">{{ label }}</label>
6
- </template>
7
- <template v-else>
8
- <input
9
- :id="uuid"
10
- v-model="inputText"
11
- v-mask="mask"
12
- class="aform_input-field"
13
- :disabled="mode === 'read'"
14
- :maxlength="mask ? (maskFilled ? mask.length : undefined) : undefined"
15
- :required="required" />
16
- <label class="aform_field-label" :for="uuid">{{ label }} </label>
17
- <p v-show="errorText" class="aform_error" v-html="errorText"></p>
18
- </template>
19
- </div>
20
- </template>
21
-
22
- <script setup lang="ts">
23
- import { /* inject, */ computed, ref } from 'vue'
24
-
25
- import { useStringMask as vMask } from '../../directives/mask'
26
- import { ComponentProps } from '../../types'
27
-
28
- const { label, mask, required, mode, uuid, errors, validation = { errorMessage: '' } } = defineProps<ComponentProps>()
29
-
30
- // Dynamic trigger errors take precedence over a static schema errorMessage; empty means the slot hides.
31
- const errorText = computed(() => (errors?.length ? errors.join('; ') : (validation.errorMessage ?? '')))
32
-
33
- // TODO: setup maskFilled as a computed property
34
- const maskFilled = ref(true)
35
-
36
- // TODO: (state) replace with state management
37
- // const locale = inject<string>('locale', '')
38
-
39
- const inputText = defineModel<number | string>()
40
- </script>
@@ -1,66 +0,0 @@
1
- <template>
2
- <div class="aform_form-element">
3
- <template v-if="mode === 'display'">
4
- <span class="aform_display-value aform_textbox-display">{{ inputText ?? '' }}</span>
5
- <label class="aform_field-label">{{ label }}</label>
6
- </template>
7
- <template v-else>
8
- <textarea
9
- :id="uuid"
10
- v-model="inputText"
11
- class="aform_input-field aform_textbox"
12
- :placeholder="placeholder"
13
- :rows="rows"
14
- :maxlength="maxlength"
15
- :disabled="mode === 'read'"
16
- :required="required"></textarea>
17
- <label class="aform_field-label" :for="uuid">{{ label }}</label>
18
- <p v-show="errorText" class="aform_error" v-html="errorText"></p>
19
- </template>
20
- </div>
21
- </template>
22
-
23
- <script setup lang="ts">
24
- import { computed } from 'vue'
25
-
26
- import { ComponentProps } from '../../types'
27
-
28
- const {
29
- label,
30
- required,
31
- mode,
32
- uuid,
33
- errors,
34
- placeholder = '',
35
- rows = 4,
36
- maxlength,
37
- validation = { errorMessage: '' },
38
- } = defineProps<
39
- ComponentProps & {
40
- /** Placeholder shown when the field is empty */
41
- placeholder?: string
42
- /** Visible number of text lines (maps to the textarea `rows` attribute) */
43
- rows?: number
44
- /** Maximum number of characters the field will accept */
45
- maxlength?: number
46
- }
47
- >()
48
-
49
- // Dynamic trigger errors take precedence over a static schema errorMessage; empty means the slot hides.
50
- const errorText = computed(() => (errors?.length ? errors.join('; ') : (validation.errorMessage ?? '')))
51
-
52
- const inputText = defineModel<string | null>()
53
- </script>
54
-
55
- <style scoped>
56
- .aform_textbox {
57
- resize: vertical;
58
- line-height: 1.5;
59
- min-height: 4rem;
60
- font-family: inherit;
61
- }
62
-
63
- .aform_textbox-display {
64
- white-space: pre-wrap;
65
- }
66
- </style>
@@ -1,189 +0,0 @@
1
- <template>
2
- <div class="login-container">
3
- <div>
4
- <div class="account-container">
5
- <div class="account-header">
6
- <h1 id="account-title">{{ headerTitle }}</h1>
7
- <p id="account-subtitle">{{ headerSubtitle }}</p>
8
- </div>
9
-
10
- <form @submit="onSubmit">
11
- <div class="login-form-container">
12
- <div class="login-form-email aform_form-element">
13
- <label id="login-email" for="email" class="aform_field-label">Email</label>
14
- <input
15
- id="email"
16
- v-model="email"
17
- class="aform_input-field"
18
- name="email"
19
- placeholder="name@example.com"
20
- type="email"
21
- auto-capitalize="none"
22
- auto-complete="email"
23
- auto-correct="off"
24
- :disabled="isLoading" />
25
- </div>
26
-
27
- <div class="login-form-password aform_form-element">
28
- <label id="login-password" for="password" class="aform_field-label">Password</label>
29
- <input
30
- id="password"
31
- v-model="password"
32
- class="aform_input-field"
33
- name="password"
34
- type="password"
35
- :disabled="isLoading" />
36
- </div>
37
-
38
- <button class="btn" :disabled="isLoading || !email || !password" @click="onSubmit">
39
- <span v-if="isLoading" class="material-symbols-outlined loading-icon">progress_activity</span>
40
- <span id="login-form-button">Login</span>
41
- </button>
42
- </div>
43
- </form>
44
-
45
- <button class="btn">
46
- <span id="forgot-password-button">Forgot password?</span>
47
- </button>
48
- </div>
49
- </div>
50
- </div>
51
- </template>
52
-
53
- <script setup lang="ts">
54
- import { ref } from 'vue'
55
-
56
- const { headerTitle = 'Login', headerSubtitle = 'Enter your email and password to login' } = defineProps<{
57
- headerTitle?: string
58
- headerSubtitle?: string
59
- }>()
60
-
61
- const emit = defineEmits(['loginFailed', 'loginSuccess'])
62
-
63
- const email = ref('')
64
- const password = ref('')
65
-
66
- const isLoading = ref(false)
67
- const loginFailed = ref(false)
68
-
69
- function onSubmit(event: Event) {
70
- event.preventDefault()
71
- isLoading.value = true
72
-
73
- // TODO: handle submit logic, handle failure
74
-
75
- if (loginFailed.value) {
76
- isLoading.value = false
77
- emit('loginFailed')
78
- return
79
- }
80
-
81
- isLoading.value = false
82
- emit('loginSuccess')
83
- }
84
- </script>
85
-
86
- <style scoped>
87
- .login-container {
88
- width: 100%;
89
- position: relative;
90
- display: flex;
91
- flex-direction: column;
92
- align-items: center;
93
- justify-content: center;
94
- font-family: var(--sc-font-family);
95
- }
96
-
97
- .account-container {
98
- width: 100%;
99
- margin-left: auto;
100
- margin-top: 0.5rem;
101
- margin-right: auto;
102
- display: flex;
103
- flex-direction: column;
104
- justify-content: center;
105
- }
106
-
107
- .account-header {
108
- display: flex;
109
- flex-direction: column;
110
- text-align: center;
111
- margin-top: 0.5rem;
112
- }
113
-
114
- #account-title {
115
- font-size: 1.5rem;
116
- line-height: 2rem;
117
- font-weight: 600;
118
- letter-spacing: -0.025em;
119
- margin: 0;
120
- }
121
-
122
- #account-subtitle {
123
- font-size: 0.875rem;
124
- line-height: 1.25rem;
125
- margin: 1rem;
126
- }
127
-
128
- .login-form-container {
129
- display: grid;
130
- gap: 0.5rem;
131
- }
132
-
133
- .login-form-element {
134
- display: grid;
135
- margin: 0.5rem 0;
136
- position: relative;
137
- }
138
- .login-field {
139
- padding: 0.5rem 0.25rem 0.25rem 0.5rem;
140
- outline: 1px solid transparent;
141
- border: 1px solid var(--sc-input-border-color);
142
- border-radius: 0.25rem;
143
-
144
- &:focus {
145
- border: 1px solid black;
146
- }
147
- }
148
-
149
- .btn {
150
- background-color: var(--sc-btn-color);
151
- color: var(--sc-btn-label-color);
152
- border: 1px solid var(--sc-btn-border);
153
- margin: 0.5rem 0;
154
- padding: 0.25rem;
155
- position: relative;
156
- cursor: pointer;
157
-
158
- &:hover {
159
- background-color: var(--sc-btn-hover);
160
- }
161
-
162
- &:disabled {
163
- background-color: var(--sc-input-field-disabled-background);
164
- }
165
- }
166
- .disabled {
167
- opacity: 0.5;
168
- }
169
- .loading-icon {
170
- animation: spin 1s linear infinite forwards;
171
- display: inline-block;
172
- margin-right: 0.2rem;
173
- line-height: 0;
174
- font-size: 1rem;
175
- position: relative;
176
- top: 0.2rem;
177
- }
178
-
179
- /* ANIMATION */
180
- @keyframes spin {
181
- from {
182
- transform: rotate(0deg);
183
- }
184
-
185
- to {
186
- transform: rotate(360deg);
187
- }
188
- }
189
- </style>
@@ -1,122 +0,0 @@
1
- import type { DirectiveBinding } from 'vue'
2
-
3
- import { deserializeFunction } from '../utils/deserialize'
4
-
5
- /**
6
- * Extracts a mask function from a stringified function
7
- * @param mask - Mask string
8
- * @returns Mask function, or undefined if the string is not a valid function expression
9
- */
10
- function extractMaskFn(mask: string): ((locale: any) => string) | undefined {
11
- try {
12
- return deserializeFunction<(locale: any) => string>(mask)
13
- } catch {
14
- return undefined
15
- }
16
- }
17
-
18
- /**
19
- * Gets the mask for a given directive binding
20
- * @param binding - Binding object from directive hook
21
- * @returns Mask string
22
- */
23
- function getMask(binding: DirectiveBinding<string>) {
24
- const mask = binding.value
25
- if (!mask) return undefined
26
-
27
- const maskFn = extractMaskFn(mask)
28
- if (maskFn) {
29
- // TODO: (state) replace with state management;
30
- // pass the entire form/table data to the function
31
- // Vue directive reads arbitrary fields off host component instance; type is unknown at this layer.
32
- // oxlint-disable-next-line typescript/no-unsafe-type-assertion
33
- const instance = binding.instance as Record<string, unknown> | null | undefined
34
- // oxlint-disable-next-line typescript/no-unsafe-type-assertion
35
- const locale = instance?.['locale'] as string | undefined
36
- return maskFn(locale)
37
- }
38
-
39
- return mask
40
- }
41
-
42
- /**
43
- * Unmasks the input string
44
- * @param input - Input string
45
- * @param maskToken - Mask token character
46
- * @returns Unmasked input string
47
- */
48
- function unmaskInput(input: string, maskToken?: string) {
49
- if (!maskToken) {
50
- maskToken = '#'
51
- }
52
-
53
- let unmaskedInput = input
54
- const maskChars = [maskToken, '/', '-', '(', ')', ' ']
55
-
56
- for (const char of maskChars) {
57
- unmaskedInput = unmaskedInput.replaceAll(char, '')
58
- }
59
-
60
- return unmaskedInput
61
- }
62
-
63
- /**
64
- * Fills the mask with the input string
65
- * @param input - Input string
66
- * @param mask - Mask string
67
- * @param maskToken - Mask token character
68
- * @returns Masked input string
69
- */
70
- function fillMask(input: string, mask: string, maskToken?: string) {
71
- if (!maskToken) {
72
- maskToken = '#'
73
- }
74
-
75
- let replacement = mask
76
- for (const inputChar of input) {
77
- const replaceIndex = replacement.indexOf(maskToken)
78
- if (replaceIndex !== -1) {
79
- const prefix = replacement.substring(0, replaceIndex)
80
- const suffix = replacement.substring(replaceIndex + 1)
81
- replacement = prefix + inputChar + suffix
82
- }
83
- }
84
-
85
- return replacement.slice(0, mask.length)
86
- }
87
-
88
- /**
89
- * Applies a mask to an input element
90
- * @param el - Input element
91
- * @param binding - Binding object from directive hook
92
- * @returns void
93
- * @public
94
- */
95
- export function useStringMask(el: HTMLInputElement, binding: DirectiveBinding<string>) {
96
- const mask = getMask(binding)
97
- if (!mask) return
98
-
99
- const maskToken = '#'
100
- const inputText = el.value
101
-
102
- // process input value with mask
103
- const unmaskedInput = unmaskInput(inputText, maskToken)
104
- if (unmaskedInput) {
105
- const replacement = fillMask(unmaskedInput, mask, maskToken)
106
-
107
- // TODO: (state) this is very opinionated;
108
- // most likely fixed with state management;
109
- // a better way could be to emit back to instance;
110
-
111
- // Vue directive reads/writes arbitrary fields on host component instance.
112
- // oxlint-disable-next-line typescript/no-unsafe-type-assertion
113
- const instance = binding.instance as Record<string, unknown> | null | undefined
114
- if (instance?.['maskFilled']) {
115
- instance['maskFilled'] = !replacement.includes(maskToken)
116
- }
117
-
118
- el.value = replacement
119
- } else {
120
- el.value = mask
121
- }
122
- }
package/src/index.ts DELETED
@@ -1,92 +0,0 @@
1
- export type * from '@stonecrop/atable/types'
2
- export { deserializeFunction } from './utils/deserialize'
3
- export { badgeInputAccentStyle, resolveFieldBadge } from './utils/badge'
4
- export { resolvedFieldsToColumns } from './utils/columns'
5
- export type { BadgeFormatContext, BadgeFormatFn } from './utils/badge'
6
- import { install as installATable } from '@stonecrop/atable'
7
- import type { App } from 'vue'
8
-
9
- import ACheckbox from './components/form/ACheckbox.vue'
10
- import ACurrencyInput from './components/form/ACurrencyInput.vue'
11
- import ADate from './components/form/ADate.vue'
12
- import ADropdown from './components/form/ADropdown.vue'
13
- import ASegmentedControl from './components/form/ASegmentedControl.vue'
14
- import ABadge from './components/form/ABadge.vue'
15
- import ADatePicker from './components/form/ADatePicker.vue'
16
- import ADateTime from './components/form/ADateTime.vue'
17
- import ADateTimeInput from './components/form/ADateTimeInput.vue'
18
- import ADateSelection from './components/form/ADateSelection.vue'
19
- import ADuration from './components/form/ADuration.vue'
20
- import ADateRange from './components/form/ADateRange.vue'
21
- import AFieldset from './components/form/AFieldset.vue'
22
- import AFileAttach from './components/form/AFileAttach.vue'
23
- import AForm from './components/AForm.vue'
24
- import AFormLink from './components/form/AFormLink.vue'
25
- import ANumericInput from './components/form/ANumericInput.vue'
26
- import AQuantityInput from './components/form/AQuantityInput.vue'
27
- import ATextInput from './components/form/ATextInput.vue'
28
- import ATextboxInput from './components/form/ATextboxInput.vue'
29
- import Login from './components/utilities/Login.vue'
30
- import AFormLoading from './components/AFormLoading.vue'
31
- import ExpandButton from './components/base/ExpandButton.vue'
32
-
33
- export type * from './types'
34
-
35
- /**
36
- * Install all AForm components
37
- * @param app - Vue app instance
38
- * @public
39
- */
40
- function install(app: App /* options */) {
41
- app.use(installATable) // Install ATable components for use within AForm
42
-
43
- app.component('ACheckbox', ACheckbox)
44
- app.component('ACurrencyInput', ACurrencyInput)
45
- app.component('ADate', ADate)
46
- app.component('ADropdown', ADropdown)
47
- app.component('ASegmentedControl', ASegmentedControl)
48
- app.component('ABadge', ABadge)
49
- app.component('ADatePicker', ADatePicker)
50
- app.component('ADateTime', ADateTime)
51
- app.component('ADateTimeInput', ADateTimeInput)
52
- app.component('ADateRange', ADateRange)
53
- app.component('ADateSelection', ADateSelection)
54
- app.component('AFieldset', AFieldset)
55
- app.component('AFileAttach', AFileAttach)
56
- app.component('AForm', AForm)
57
- app.component('AFormLink', AFormLink)
58
- app.component('ANumericInput', ANumericInput)
59
- app.component('AQuantityInput', AQuantityInput)
60
- app.component('ATextInput', ATextInput)
61
- app.component('ATextboxInput', ATextboxInput)
62
- app.component('ADuration', ADuration)
63
- app.component('AFormLoading', AFormLoading)
64
- app.component('ExpandButton', ExpandButton)
65
- }
66
-
67
- export {
68
- ACheckbox,
69
- ACurrencyInput,
70
- ADate,
71
- ADropdown,
72
- ASegmentedControl,
73
- ABadge,
74
- ADatePicker,
75
- ADateRange,
76
- ADateSelection,
77
- ADuration,
78
- ADateTime,
79
- ADateTimeInput,
80
- AFieldset,
81
- AFileAttach,
82
- AForm,
83
- AFormLink,
84
- ANumericInput,
85
- AQuantityInput,
86
- ATextInput,
87
- ATextboxInput,
88
- Login,
89
- AFormLoading,
90
- ExpandButton,
91
- install,
92
- }
@@ -1,5 +0,0 @@
1
- declare module '*.vue' {
2
- import { ComponentOptions } from 'vue'
3
- const Component: ComponentOptions
4
- export default Component
5
- }