@globalbrain/sefirot 2.17.0 → 2.19.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.
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { IconifyIcon } from '@iconify/vue/dist/offline'
3
- import { DefineComponent, ref } from 'vue'
3
+ import { DefineComponent, computed, ref } from 'vue'
4
4
  import { Validatable } from '../composables/Validation'
5
5
  import SInputBase from './SInputBase.vue'
6
6
 
@@ -28,15 +28,23 @@ const props = defineProps<{
28
28
  noMinute?: boolean
29
29
  noSecond?: boolean
30
30
  disabled?: boolean
31
- hideError?: boolean
32
- modelValue: Value
31
+ value?: Value
32
+ modelValue?: Value
33
33
  validation?: Validatable
34
+ hideError?: boolean
34
35
  }>()
35
36
 
36
37
  const emit = defineEmits<{
37
- (e: 'update:modelValue', value: Value): void
38
+ (e: 'update:model-value', value: Value): void
39
+ (e: 'change', value: Value): void
38
40
  }>()
39
41
 
42
+ const _value = computed(() => {
43
+ return props.modelValue !== undefined
44
+ ? props.modelValue
45
+ : props.value !== undefined ? props.value : null
46
+ })
47
+
40
48
  const isFocused = ref(false)
41
49
 
42
50
  const touched = {
@@ -66,10 +74,17 @@ function updateSecond(e: FocusEvent): void {
66
74
  }
67
75
 
68
76
  function update(type: ValueType, value: string | null) {
69
- emit('update:modelValue', {
70
- ...props.modelValue,
77
+ if (_value.value === null) {
78
+ return
79
+ }
80
+
81
+ const newValue = {
82
+ ..._value.value,
71
83
  [type]: value !== null ? value.padStart(2, '0') : null
72
- })
84
+ }
85
+
86
+ emit('update:model-value', newValue)
87
+ emit('change', newValue)
73
88
 
74
89
  emitTouch(type)
75
90
 
@@ -114,7 +129,7 @@ function createRequiredTouched(): boolean[] {
114
129
  <template>
115
130
  <SInputBase
116
131
  class="SInputHMS"
117
- :class="[size, { disabled }]"
132
+ :class="[size ?? 'small', { disabled }]"
118
133
  :label="label"
119
134
  :note="note"
120
135
  :info="info"
@@ -129,8 +144,9 @@ function createRequiredTouched(): boolean[] {
129
144
  <input
130
145
  v-if="!noHour"
131
146
  class="input hour"
132
- :value="modelValue.hour"
147
+ :value="_value?.hour"
133
148
  placeholder="00"
149
+ :maxlength="2"
134
150
  :disabled="disabled"
135
151
  @focus="onFocus"
136
152
  @blur="updateHour"
@@ -139,8 +155,9 @@ function createRequiredTouched(): boolean[] {
139
155
  <input
140
156
  v-if="!noMinute"
141
157
  class="input minute"
142
- :value="modelValue.minute"
158
+ :value="_value?.minute"
143
159
  placeholder="00"
160
+ :maxlength="2"
144
161
  :disabled="disabled"
145
162
  @focus="onFocus"
146
163
  @blur="updateMinute"
@@ -149,8 +166,9 @@ function createRequiredTouched(): boolean[] {
149
166
  <input
150
167
  v-if="!noSecond"
151
168
  class="input second"
152
- :value="modelValue.second"
169
+ :value="_value?.second"
153
170
  placeholder="00"
171
+ :maxlength="2"
154
172
  :disabled="disabled"
155
173
  @focus="onFocus"
156
174
  @blur="updateSecond"
@@ -170,15 +188,15 @@ function createRequiredTouched(): boolean[] {
170
188
 
171
189
  .input {
172
190
  padding: 3px 0;
173
- text-align: center;
174
- font-size: 14px;
175
191
  width: 20px;
192
+ text-align: center;
193
+ font-size: var(--input-font-size, var(--input-mini-font-size));
176
194
  }
177
195
 
178
196
  .separator {
179
197
  padding: 3px 0;
180
198
  line-height: 24px;
181
- font-size: 14px;
199
+ font-size: var(--input-font-size, var(--input-mini-font-size));
182
200
  }
183
201
 
184
202
  .separator::before {
@@ -189,20 +207,21 @@ function createRequiredTouched(): boolean[] {
189
207
  .SInputHMS.small {
190
208
  .container {
191
209
  padding: 0 12px;
210
+ min-height: 40px;
192
211
  }
193
212
 
194
213
  .input {
195
214
  flex-shrink: 0;
196
- padding: 8px 0 6px;
197
- text-align: center;
198
- font-size: 16px;
215
+ padding: 7px 0 6px;
199
216
  width: 20px;
217
+ text-align: center;
218
+ font-size: var(--input-font-size, var(--input-small-font-size));
200
219
  }
201
220
 
202
221
  .separator {
203
222
  padding: 7px 0;
204
223
  line-height: 24px;
205
- font-size: 16px;
224
+ font-size: var(--input-font-size, var(--input-small-font-size));
206
225
  }
207
226
 
208
227
  .separator::before {
@@ -218,14 +237,14 @@ function createRequiredTouched(): boolean[] {
218
237
  .input {
219
238
  padding: 12px 0 10px;
220
239
  text-align: center;
221
- font-size: 16px;
240
+ font-size: var(--input-font-size, var(--input-medium-font-size));
222
241
  width: 24px;
223
242
  }
224
243
 
225
244
  .separator {
226
245
  padding: 11px 0;
227
246
  line-height: 24px;
228
- font-size: 16px;
247
+ font-size: var(--input-font-size, var(--input-medium-font-size));
229
248
  }
230
249
 
231
250
  .separator::before {
@@ -240,49 +259,37 @@ function createRequiredTouched(): boolean[] {
240
259
  }
241
260
 
242
261
  .container {
243
- border-color: var(--input-border);
244
- background-color: var(--input-disabled-bg);
262
+ background-color: var(--input-disabled-bg-color);
245
263
  }
264
+
265
+ .container:hover { border-color: var(--input-border-color); }
266
+ .container.focus { border-color: var(--input-border-color); }
246
267
  }
247
268
 
248
269
  .SInputHMS.has-error {
249
270
  .container {
250
- border-color: var(--c-danger);
271
+ border-color: var(--input-error-border-color);
251
272
  }
252
273
  }
253
274
 
254
275
  .container {
255
276
  display: inline-flex;
256
- border: 1px solid var(--c-divider);
277
+ border: 1px solid var(--input-border-color);
257
278
  border-radius: 6px;
258
- background-color: var(--c-bg);
279
+ background-color: var(--input-bg-color);
259
280
  transition: border-color 0.25s;
260
281
 
261
- &:hover {
262
- border-color: var(--c-black);
263
- }
264
-
265
- &.focus,
266
- &:hover.focus {
267
- border-color: var(--c-info);
268
- }
269
-
270
- .dark &:hover {
271
- border-color: var(--c-gray);
272
- }
273
-
274
- .dark &.focus,
275
- .dark &:hover.focus {
276
- border-color: var(--c-info);
277
- }
282
+ &:hover { border-color: var(--input-hover-border-color); }
283
+ &.focus { border-color: var(--input-focus-border-color); }
278
284
  }
279
285
 
280
286
  .input {
287
+ font-family: var(--font-family-number);
288
+ line-height: 24px;
281
289
  background-color: transparent;
282
290
 
283
291
  &::placeholder {
284
- font-weight: 500;
285
- color: var(--c-text-3);
292
+ color: var(--input-placeholder-color);
286
293
  }
287
294
  }
288
295
 
@@ -2,12 +2,13 @@
2
2
  import { IconifyIcon } from '@iconify/vue/dist/offline'
3
3
  import { DefineComponent, computed } from 'vue'
4
4
  import { Validatable } from '../composables/Validation'
5
- import { isNullish } from '../support/Utils'
5
+ import { isNullish, isString } from '../support/Utils'
6
6
  import SInputText from './SInputText.vue'
7
7
 
8
8
  export type Size = 'mini' | 'small' | 'medium'
9
9
  export type Align = 'left' | 'center' | 'right'
10
- export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
10
+ export type CheckColor = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
11
+ export type TextColor = 'neutral' | 'info' | 'success' | 'warning' | 'danger'
11
12
 
12
13
  const props = defineProps<{
13
14
  size?: Size
@@ -21,7 +22,8 @@ const props = defineProps<{
21
22
  unitAfter?: any
22
23
  checkIcon?: IconifyIcon | DefineComponent
23
24
  checkText?: string
24
- checkColor?: Color
25
+ checkColor?: CheckColor
26
+ textColor?: TextColor | ((value: number | null) => TextColor)
25
27
  align?: Align
26
28
  separator?: boolean
27
29
  disabled?: boolean
@@ -43,6 +45,18 @@ const _value = computed(() => {
43
45
  : props.value !== undefined ? props.value : null
44
46
  })
45
47
 
48
+ const _textColor = computed(() => {
49
+ if (!props.textColor) {
50
+ return 'neutral'
51
+ }
52
+
53
+ if (isString(props.textColor)) {
54
+ return props.textColor
55
+ }
56
+
57
+ return props.textColor(_value.value)
58
+ })
59
+
46
60
  const valueWithSeparator = computed(() => {
47
61
  if (isNullish(_value.value)) {
48
62
  return null
@@ -86,6 +100,7 @@ function emitUpdate(value: string | null) {
86
100
  :check-icon="checkIcon"
87
101
  :check-text="checkText"
88
102
  :check-color="checkColor"
103
+ :text-color="_textColor"
89
104
  :align="align"
90
105
  :disabled="disabled"
91
106
  :hide-error="hideError"
@@ -8,7 +8,8 @@ import SInputBase from './SInputBase.vue'
8
8
 
9
9
  export type Size = 'mini' | 'small' | 'medium'
10
10
  export type Align = 'left' | 'center' | 'right'
11
- export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
11
+ export type CheckColor = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
12
+ export type TextColor = 'neutral' | 'info' | 'success' | 'warning' | 'danger'
12
13
 
13
14
  const props = defineProps<{
14
15
  size?: Size
@@ -23,7 +24,8 @@ const props = defineProps<{
23
24
  unitAfter?: any
24
25
  checkIcon?: IconifyIcon | DefineComponent
25
26
  checkText?: string
26
- checkColor?: Color
27
+ checkColor?: CheckColor
28
+ textColor?: TextColor | ((value: string | null) => TextColor)
27
29
  align?: Align
28
30
  disabled?: boolean
29
31
  modelValue: string | null
@@ -48,6 +50,23 @@ const classes = computed(() => [
48
50
  { disabled: props.disabled }
49
51
  ])
50
52
 
53
+ const inputClasses = computed(() => [
54
+ textColor.value,
55
+ { hide: showDisplay.value }
56
+ ])
57
+
58
+ const textColor = computed(() => {
59
+ if (!props.textColor) {
60
+ return 'neutral'
61
+ }
62
+
63
+ if (isString(props.textColor)) {
64
+ return props.textColor
65
+ }
66
+
67
+ return props.textColor(props.modelValue)
68
+ })
69
+
51
70
  const showDisplay = computed(() => {
52
71
  return !isFocused.value && props.displayValue
53
72
  })
@@ -122,7 +141,7 @@ function getValue(e: Event | FocusEvent | KeyboardEvent): string | null {
122
141
  <div class="area">
123
142
  <input
124
143
  class="input entity"
125
- :class="{ hide: showDisplay }"
144
+ :class="inputClasses"
126
145
  :id="name"
127
146
  :type="type ?? 'text'"
128
147
  :placeholder="placeholder"
@@ -134,7 +153,7 @@ function getValue(e: Event | FocusEvent | KeyboardEvent): string | null {
134
153
  @input="emitInput"
135
154
  @keypress.enter="emitEnter"
136
155
  >
137
- <div v-if="showDisplay" class="input display">
156
+ <div v-if="showDisplay" class="input display" :class="[textColor]">
138
157
  {{ displayValue }}
139
158
  </div>
140
159
  </div>
@@ -371,10 +390,15 @@ function getValue(e: Event | FocusEvent | KeyboardEvent): string | null {
371
390
  bottom: 0;
372
391
  left: 0;
373
392
  width: 100%;
374
- color: var(--input-value-color);
375
393
  background-color: transparent;
376
394
  cursor: text;
377
395
 
396
+ &.neutral:not(.hide) { color: var(--input-value-color); }
397
+ &.info:not(.hide) { color: var(--c-info-text); }
398
+ &.success:not(.hide) { color: var(--c-success-text); }
399
+ &.warning:not(.hide) { color: var(--c-warning-text); }
400
+ &.danger:not(.hide) { color: var(--c-danger-text); }
401
+
378
402
  &.hide,
379
403
  &.hide::placeholder {
380
404
  color: transparent;
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { IconifyIcon } from '@iconify/vue/dist/offline'
3
- import { DefineComponent, ref } from 'vue'
3
+ import { DefineComponent, computed, ref } from 'vue'
4
4
  import { Validatable } from '../composables/Validation'
5
5
  import SInputBase from './SInputBase.vue'
6
6
 
@@ -28,15 +28,31 @@ const props = defineProps<{
28
28
  noMonth?: boolean
29
29
  noDate?: boolean
30
30
  disabled?: boolean
31
- hideError?: boolean
32
- modelValue: Value
31
+ value?: Value
32
+ modelValue?: Value
33
33
  validation?: Validatable
34
+ hideError?: boolean
34
35
  }>()
35
36
 
36
37
  const emit = defineEmits<{
37
- (e: 'update:modelValue', value: Value): void
38
+ (e: 'update:model-value', value: Value): void
39
+ (e: 'change', value: Value): void
38
40
  }>()
39
41
 
42
+ const _value = computed(() => {
43
+ return props.modelValue !== undefined
44
+ ? props.modelValue
45
+ : props.value !== undefined ? props.value : null
46
+ })
47
+
48
+ const padValue = computed(() => {
49
+ return {
50
+ year: _value.value?.year?.toString().padStart(4, '0') ?? null,
51
+ month: _value.value?.month?.toString().padStart(2, '0') ?? null,
52
+ date: _value.value?.date?.toString().padStart(2, '0') ?? null
53
+ }
54
+ })
55
+
40
56
  const isFocused = ref(false)
41
57
 
42
58
  const touched = {
@@ -54,22 +70,29 @@ function blur() {
54
70
  }
55
71
 
56
72
  function updateYear(e: FocusEvent) {
57
- update('year', Number((e.target as HTMLInputElement).value))
73
+ update('year', (e.target as HTMLInputElement).value)
58
74
  }
59
75
 
60
76
  function updateMonth(e: FocusEvent) {
61
- update('month', Number((e.target as HTMLInputElement).value))
77
+ update('month', (e.target as HTMLInputElement).value)
62
78
  }
63
79
 
64
80
  function updateDate(e: FocusEvent) {
65
- update('date', Number((e.target as HTMLInputElement).value))
81
+ update('date', (e.target as HTMLInputElement).value)
66
82
  }
67
83
 
68
- function update(type: ValueType, value: number) {
69
- emit('update:modelValue', {
70
- ...props.modelValue,
71
- [type]: value === 0 ? null : value
72
- })
84
+ function update(type: ValueType, value: string) {
85
+ if (_value.value === null) {
86
+ return
87
+ }
88
+
89
+ const newValue = {
90
+ ..._value.value,
91
+ [type]: value ? Number(value) : null
92
+ }
93
+
94
+ emit('update:model-value', newValue)
95
+ emit('change', newValue)
73
96
 
74
97
  emitTouch(type)
75
98
 
@@ -119,9 +142,9 @@ function createRequiredTouched(): boolean[] {
119
142
  <input
120
143
  v-if="!noYear"
121
144
  class="input year"
122
- type="number"
123
- :value="modelValue.year"
124
- placeholder="YYYY"
145
+ :value="padValue?.year"
146
+ placeholder="1998"
147
+ :maxlength="4"
125
148
  :disabled="disabled"
126
149
  @focus="onFocus"
127
150
  @blur="updateYear"
@@ -133,9 +156,9 @@ function createRequiredTouched(): boolean[] {
133
156
  <input
134
157
  v-if="!noMonth"
135
158
  class="input month"
136
- type="number"
137
- :value="modelValue.month"
138
- placeholder="M"
159
+ :value="padValue?.month"
160
+ placeholder="01"
161
+ :maxlength="2"
139
162
  :disabled="disabled"
140
163
  @focus="onFocus"
141
164
  @blur="updateMonth"
@@ -147,9 +170,9 @@ function createRequiredTouched(): boolean[] {
147
170
  <input
148
171
  v-if="!noDate"
149
172
  class="input date"
150
- type="number"
151
- :value="modelValue.date"
152
- placeholder="D"
173
+ :value="padValue?.date"
174
+ placeholder="14"
175
+ :maxlength="2"
153
176
  :disabled="disabled"
154
177
  @focus="onFocus"
155
178
  @blur="updateDate"
@@ -159,7 +182,7 @@ function createRequiredTouched(): boolean[] {
159
182
  </SInputBase>
160
183
  </template>
161
184
 
162
- <style lang="postcss" scoped>
185
+ <style scoped lang="postcss">
163
186
  .SInputYMD.mini {
164
187
  .container {
165
188
  padding: 0 4px;
@@ -168,7 +191,7 @@ function createRequiredTouched(): boolean[] {
168
191
  .input {
169
192
  padding: 3px 0;
170
193
  text-align: center;
171
- font-size: 14px;
194
+ font-size: var(--input-font-size, var(--input-mini-font-size));
172
195
  }
173
196
 
174
197
  .input.year { width: 48px; }
@@ -178,51 +201,53 @@ function createRequiredTouched(): boolean[] {
178
201
  .separator {
179
202
  padding: 3px 0;
180
203
  line-height: 24px;
181
- font-size: 14px;
204
+ font-size: var(--input-font-size, var(--input-mini-font-size));
182
205
  }
183
206
  }
184
207
 
185
208
  .SInputYMD.small {
186
209
  .container {
187
- padding: 0 6px;
210
+ padding: 0 8px;
188
211
  }
189
212
 
190
213
  .input {
191
- padding: 7px 0;
214
+ padding: 7px 0 6px;
192
215
  text-align: center;
193
- font-size: 16px;
216
+ font-size: var(--input-font-size, var(--input-small-font-size));
194
217
  }
195
218
 
196
- .input.year { width: 56px; }
219
+ .input.year { margin-right: 2px; }
220
+ .input.year { width: 48px; }
197
221
  .input.month { width: 32px; }
198
- .input.date { width: 40px; }
222
+ .input.date { width: 32px; }
199
223
 
200
224
  .separator {
201
225
  padding: 7px 0;
202
226
  line-height: 24px;
203
- font-size: 16px;
227
+ font-size: var(--input-font-size, var(--input-small-font-size));
204
228
  }
205
229
  }
206
230
 
207
231
  .SInputYMD.medium {
208
232
  .container {
209
- padding: 0 4px;
233
+ padding: 0 8px;
210
234
  }
211
235
 
212
236
  .input {
213
237
  padding: 11px 0;
214
238
  text-align: center;
215
- font-size: 16px;
239
+ font-size: var(--input-font-size, var(--input-medium-font-size));
216
240
  }
217
241
 
218
- .input.year { width: 56px; }
219
- .input.month { width: 40px; }
220
- .input.date { width: 40px; }
242
+ .input.year { margin-right: 2px; }
243
+ .input.year { width: 52px; }
244
+ .input.month { width: 36px; }
245
+ .input.date { width: 36px; }
221
246
 
222
247
  .separator {
223
248
  padding: 11px 0;
224
249
  line-height: 24px;
225
- font-size: 16px;
250
+ font-size: var(--input-font-size, var(--input-medium-font-size));
226
251
  }
227
252
  }
228
253
 
@@ -233,48 +258,34 @@ function createRequiredTouched(): boolean[] {
233
258
  }
234
259
 
235
260
  .container {
236
- background-color: var(--input-disabled-bg);
261
+ background-color: var(--input-disabled-bg-color);
237
262
  }
238
263
  }
239
264
 
240
265
  .SInputYMD.has-error {
241
266
  .container {
242
- border-color: var(--c-danger);
267
+ border-color: var(--input-error-border-color);
243
268
  }
244
269
  }
245
270
 
246
271
  .container {
247
272
  display: inline-flex;
248
- border: 1px solid var(--c-divider);
273
+ border: 1px solid var(--input-border-color);
249
274
  border-radius: 6px;
250
- background-color: var(--c-bg);
251
- transition: border-color 0.25s;
252
-
253
- &:hover {
254
- border-color: var(--c-black);
255
- }
275
+ background-color: var(--input-bg-color);
276
+ transition: border-color 0.25s, background-color 0.25s;
256
277
 
257
- &.focus,
258
- &:hover.focus {
259
- border-color: var(--c-info);
260
- }
261
-
262
- .dark &:hover {
263
- border-color: var(--c-gray);
264
- }
265
-
266
- .dark &.focus,
267
- .dark &:hover.focus {
268
- border-color: var(--c-info);
269
- }
278
+ &:hover { border-color: var(--input-hover-border-color); }
279
+ &.focus { border-color: var(--input-focus-border-color); }
270
280
  }
271
281
 
272
282
  .input {
283
+ font-family: var(--font-family-number);
284
+ line-height: 24px;
273
285
  background-color: transparent;
274
286
 
275
287
  &::placeholder {
276
- font-weight: 500;
277
- color: var(--c-text-3);
288
+ color: var(--input-placeholder-color);
278
289
  }
279
290
  }
280
291
 
@@ -57,6 +57,7 @@ export interface DropdownSectionFilterOptionAvatar extends DropdownSectionFilter
57
57
  }
58
58
 
59
59
  export interface ManualDropdownPosition {
60
+ container: Ref<any>
60
61
  position: Ref<'top' | 'bottom'>
61
62
  update(): void
62
63
  }
@@ -74,7 +75,7 @@ export function useManualDropdownPosition(
74
75
  const { top, bottom } = useElementBounding(el)
75
76
  const { height } = useWindowSize()
76
77
 
77
- const position = ref<'top' | 'bottom'>('bottom')
78
+ const position = ref<'top' | 'bottom'>(initPosition ?? 'bottom')
78
79
 
79
80
  const dialogHeight = 400
80
81
 
@@ -100,6 +101,7 @@ export function useManualDropdownPosition(
100
101
  }
101
102
 
102
103
  return {
104
+ container: el,
103
105
  position,
104
106
  update
105
107
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@globalbrain/sefirot",
3
- "version": "2.17.0",
3
+ "version": "2.19.0",
4
4
  "packageManager": "pnpm@7.26.2",
5
5
  "description": "Vue Components for Global Brain Design System.",
6
6
  "author": "Kia Ishii <ka.ishii@globalbrains.com>",