@globalbrain/sefirot 2.24.0 → 2.26.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.
@@ -4,6 +4,7 @@ import type { TableCell } from '../composables/Table'
4
4
  import STableCellAvatar from './STableCellAvatar.vue'
5
5
  import STableCellAvatars from './STableCellAvatars.vue'
6
6
  import STableCellDay from './STableCellDay.vue'
7
+ import STableCellEmpty from './STableCellEmpty.vue'
7
8
  import STableCellPill from './STableCellPill.vue'
8
9
  import STableCellPills from './STableCellPills.vue'
9
10
  import STableCellText from './STableCellText.vue'
@@ -41,6 +42,7 @@ const computedCell = computed<TableCell | undefined>(() =>
41
42
  v-else-if="computedCell.type === 'day'"
42
43
  :value="value"
43
44
  :record="record"
45
+ :getter="computedCell.value"
44
46
  :format="computedCell.format"
45
47
  :color="computedCell.color"
46
48
  />
@@ -73,6 +75,9 @@ const computedCell = computed<TableCell | undefined>(() =>
73
75
  :avatars="computedCell.avatars"
74
76
  :color="computedCell.color"
75
77
  />
78
+ <STableCellEmpty
79
+ v-else-if="computedCell.type === 'empty'"
80
+ />
76
81
  <component
77
82
  v-else-if="computedCell.type === 'component'"
78
83
  :is="computedCell.component"
@@ -6,19 +6,32 @@ import SLink from './SLink.vue'
6
6
  const props = defineProps<{
7
7
  value?: any
8
8
  record?: any
9
- image?(value: any, record: any): string | undefined
10
- name?(value: any, record: any): string
11
- link?(value: any, record: any): string
9
+ image?: string | null | ((value: any, record: any) => string | null | undefined)
10
+ name?: string | null | ((value: any, record: any) => string | null | undefined)
11
+ link?: string | null | ((value: any, record: any) => string | null | undefined)
12
12
  color?: 'neutral' | 'soft' | 'mute'
13
13
  }>()
14
14
 
15
- const _image = computed(() => props.image?.(props.value, props.record))
16
- const _name = computed(() => props.name?.(props.value, props.record))
15
+ const _image = computed(() => resolve(props.image))
16
+ const _name = computed(() => resolve(props.name))
17
+ const _link = computed(() => resolve(props.link))
18
+
19
+ function resolve(
20
+ value?: string | null | ((value: any, record: any) => string | null | undefined)
21
+ ) {
22
+ if (value == null || value === '') {
23
+ return null
24
+ }
25
+
26
+ return typeof value === 'function'
27
+ ? value(props.value, props.record)
28
+ : value
29
+ }
17
30
  </script>
18
31
 
19
32
  <template>
20
33
  <div class="STableCellAvatar" :class="[{ link }, color]">
21
- <SLink class="container" :href="link?.(value, record)">
34
+ <SLink class="container" :href="_link ?? undefined">
22
35
  <div v-if="_image" class="avatar">
23
36
  <SAvatar size="mini" :avatar="_image" :name="_name" />
24
37
  </div>
@@ -6,12 +6,14 @@ import SAvatar from './SAvatar.vue'
6
6
  const props = defineProps<{
7
7
  value?: any
8
8
  record?: any
9
- avatars(value: any, record: any): TableCellAvatarsOption[]
9
+ avatars: TableCellAvatarsOption[] | ((value: any, record: any) => TableCellAvatarsOption[])
10
10
  color?: 'neutral' | 'soft' | 'mute'
11
11
  }>()
12
12
 
13
13
  const _avatars = computed(() => {
14
- return props.avatars(props.value, props.record)
14
+ return typeof props.avatars === 'function'
15
+ ? props.avatars(props.value, props.record)
16
+ : props.avatars
15
17
  })
16
18
 
17
19
  const displayAvatars = computed(() => {
@@ -28,10 +30,10 @@ const names = computed(() => {
28
30
  }
29
31
 
30
32
  if (_avatars.value.length === 2) {
31
- return `${_avatars.value[0].name} and ${_avatars.value[1].name}`
33
+ return `${_avatars.value[0].name}, ${_avatars.value[1].name}`
32
34
  }
33
35
 
34
- return `${_avatars.value[0].name} +${_avatars.value.length - 1}`
36
+ return `${_avatars.value[0].name}, ${_avatars.value[1].name} +${_avatars.value.length - 1}`
35
37
  })
36
38
  </script>
37
39
 
@@ -1,18 +1,24 @@
1
1
  <script setup lang="ts">
2
+ import { computed } from 'vue'
2
3
  import type { Day } from '../support/Day'
3
4
 
4
- defineProps<{
5
+ const props = defineProps<{
5
6
  value?: Day | null
6
7
  record: any
8
+ getter?: Day | null
7
9
  format?: string
8
10
  color?: 'neutral' | 'soft' | 'mute'
9
11
  }>()
12
+
13
+ const _value = computed(() => {
14
+ return props.getter ? props.getter : props.value
15
+ })
10
16
  </script>
11
17
 
12
18
  <template>
13
19
  <div class="STableCellDay" :class="[color ?? 'neutral']">
14
- <div v-if="value" class="value">
15
- {{ value.format(format ?? 'YYYY / MM / DD HH:mm:ss') }}
20
+ <div v-if="_value" class="value">
21
+ {{ _value.format(format ?? 'YYYY / MM / DD HH:mm:ss') }}
16
22
  </div>
17
23
  </div>
18
24
  </template>
@@ -0,0 +1,9 @@
1
+ <template>
2
+ <div class="STableCellEmpty" />
3
+ </template>
4
+
5
+ <style scoped lang="postcss">
6
+ .STableCellEmpty {
7
+ min-height: 40px;
8
+ }
9
+ </style>
@@ -7,8 +7,8 @@ export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'dange
7
7
  const props = defineProps<{
8
8
  value?: any
9
9
  record: any
10
- getter?: string | ((value: any) => string)
11
- color?: Color | ((value: any) => Color)
10
+ getter?: string | ((value: any, record: any) => string)
11
+ color?: Color | ((value: any, record: any) => Color)
12
12
  }>()
13
13
 
14
14
  const _value = computed(() => {
@@ -18,7 +18,7 @@ const _value = computed(() => {
18
18
 
19
19
  return typeof props.getter === 'string'
20
20
  ? props.getter
21
- : props.getter(props.value)
21
+ : props.getter(props.value, props.record)
22
22
  })
23
23
 
24
24
  const _color = computed(() => {
@@ -28,7 +28,7 @@ const _color = computed(() => {
28
28
 
29
29
  return typeof props.color === 'string'
30
30
  ? props.color
31
- : props.color(props.value)
31
+ : props.color(props.value, props.record)
32
32
  })
33
33
  </script>
34
34
 
@@ -38,7 +38,7 @@ const _color = computed(() => {
38
38
  v-if="_value"
39
39
  size="mini"
40
40
  :mode="_color"
41
- :label="value"
41
+ :label="_value"
42
42
  />
43
43
  </div>
44
44
  </template>
@@ -16,7 +16,7 @@ const props = defineProps<{
16
16
  value?: any
17
17
  record: any
18
18
  icon?: any
19
- getter?: string | ((value: any, record: any) => string)
19
+ getter?: string | null | ((value: any, record: any) => string | null)
20
20
  color?: Color | ((value: any, record: any) => Color)
21
21
  iconColor?: Color | ((value: any, record: any) => Color)
22
22
  link?(value: any, record: any): string
@@ -28,9 +28,9 @@ const _value = computed(() => {
28
28
  return props.value
29
29
  }
30
30
 
31
- return typeof props.getter === 'string'
32
- ? props.getter
33
- : props.getter(props.value, props.record)
31
+ return typeof props.getter === 'function'
32
+ ? props.getter(props.value, props.record)
33
+ : props.getter
34
34
  })
35
35
 
36
36
  const _color = computed(() => {
@@ -9,7 +9,7 @@ import SIcon from './SIcon.vue'
9
9
 
10
10
  const props = withDefaults(defineProps<{
11
11
  name: string
12
- label: string
12
+ label?: string
13
13
  className?: string
14
14
  dropdown?: DropdownSection[]
15
15
  hasHeader: boolean
@@ -165,6 +165,7 @@ function stopDialogPositionListener() {
165
165
  .container {
166
166
  display: flex;
167
167
  justify-content: space-between;
168
+ min-height: 40px;
168
169
  padding-left: 16px;
169
170
  }
170
171
 
@@ -1,10 +1,7 @@
1
- import type { Ref } from 'vue'
2
- import { computed } from 'vue'
1
+ import { type Ref, computed, reactive, toRefs } from 'vue'
3
2
  import { useSnackbars } from '../stores/Snackbars'
4
- import type { UseDataInput } from './Data'
5
- import { useData } from './Data'
6
- import type { Validation } from './Validation'
7
- import { useValidation } from './Validation'
3
+ import { type UseDataInput, useData } from './Data'
4
+ import { type Validation, useValidation } from './Validation'
8
5
 
9
6
  export interface Form<T extends Record<string, any>> {
10
7
  data: T
@@ -15,25 +12,49 @@ export interface Form<T extends Record<string, any>> {
15
12
  validateAndNotify(): Promise<boolean>
16
13
  }
17
14
 
18
- export interface UseFormOptions<T extends Record<string, any>> {
19
- data: UseDataInput<T>
20
- rules?: Record<string, any> | ((state: T) => Record<string, any>)
15
+ export type ComputedData<T extends Record<string, () => any>> = {
16
+ [K in keyof T]: ReturnType<T[K]>
17
+ }
18
+
19
+ export type AllData<
20
+ D extends Record<string, any>,
21
+ C extends Record<string, () => any>
22
+ > = D & ComputedData<C>
23
+
24
+ export interface UseFormOptions<
25
+ D extends Record<string, any>,
26
+ C extends Record<string, () => any>
27
+ > {
28
+ data: UseDataInput<D>
29
+ computed?: (data: D) => C
30
+ rules?: Record<string, any> | ((data: AllData<D, C>) => Record<string, any>)
21
31
  }
22
32
 
23
33
  export function useForm<
24
- T extends Record<string, any>
25
- >(options: UseFormOptions<T>): Form<T> {
34
+ D extends Record<string, any> = Record<string, any>,
35
+ C extends Record<string, () => any> = Record<string, () => any>
36
+ >(options: UseFormOptions<D, C>): Form<AllData<D, C>> {
26
37
  const snackbars = useSnackbars()
27
38
 
28
39
  const data = useData(options.data)
40
+ const dataStateRef = toRefs(data.state)
41
+
42
+ const computedData = options.computed
43
+ ? createComputedData(options.computed(data.state))
44
+ : {}
45
+
46
+ const allData = reactive({
47
+ ...dataStateRef,
48
+ ...computedData
49
+ }) as AllData<D, C>
29
50
 
30
51
  const rules = computed(() => {
31
52
  return options.rules
32
- ? typeof options.rules === 'function' ? options.rules(data.state) : options.rules
53
+ ? typeof options.rules === 'function' ? options.rules(allData) : options.rules
33
54
  : {}
34
55
  })
35
56
 
36
- const validation = useValidation(data.state, rules)
57
+ const validation = useValidation(allData, rules)
37
58
 
38
59
  function init(): void {
39
60
  data.init()
@@ -62,7 +83,7 @@ export function useForm<
62
83
  }
63
84
 
64
85
  return {
65
- data: data.state,
86
+ data: allData,
66
87
  init,
67
88
  reset,
68
89
  validation,
@@ -70,3 +91,15 @@ export function useForm<
70
91
  validateAndNotify
71
92
  }
72
93
  }
94
+
95
+ function createComputedData<
96
+ C extends Record<string, () => any>
97
+ >(input: C): ComputedData<C> {
98
+ const computedData = {} as any
99
+
100
+ for (const [key, fn] of Object.entries(input)) {
101
+ computedData[key] = computed(() => fn())
102
+ }
103
+
104
+ return computedData
105
+ }
@@ -1,12 +1,16 @@
1
1
  import type { MaybeRef } from '@vueuse/core'
2
2
  import type { Component } from 'vue'
3
3
  import { reactive } from 'vue'
4
+ import type { Day } from '../support/Day'
4
5
  import type { DropdownSection } from './Dropdown'
5
6
 
6
- export interface Table {
7
- orders: string[]
8
- columns: TableColumns
9
- records?: Record<string, any>[] | null
7
+ export interface Table<
8
+ O extends string = any,
9
+ R extends Record<string, any> = any
10
+ > {
11
+ orders: O[]
12
+ columns: TableColumns<O, R>
13
+ records?: R[] | null
10
14
  header?: boolean
11
15
  footer?: boolean
12
16
  total?: number | null
@@ -20,16 +24,21 @@ export interface Table {
20
24
  onReset?(): void
21
25
  }
22
26
 
23
- export interface TableColumns {
24
- [name: string]: TableColumn
27
+ export type TableColumns<
28
+ O extends string,
29
+ R extends Record<string, any>
30
+ > = {
31
+ [K in O]: K extends keyof R
32
+ ? TableColumn<R[K], R>
33
+ : TableColumn<undefined, R>
25
34
  }
26
35
 
27
- export interface TableColumn {
28
- label: string
36
+ export interface TableColumn<V, R> {
37
+ label?: string
29
38
  className?: string
30
39
  dropdown?: DropdownSection[]
31
40
  resizable?: boolean
32
- cell?: TableCell | ((value: any, record: any) => TableCell)
41
+ cell?: TableCell | ((value: V, record: R) => TableCell)
33
42
  }
34
43
 
35
44
  export type TableCell =
@@ -39,9 +48,18 @@ export type TableCell =
39
48
  | TableCellPills
40
49
  | TableCellAvatar
41
50
  | TableCellAvatars
51
+ | TableCellEmpty
42
52
  | TableCellComponent
43
53
 
44
- export type TableCellType = 'text' | 'day' | 'pill' | 'pills' | 'avatar' | 'avatars' | 'component'
54
+ export type TableCellType =
55
+ | 'text'
56
+ | 'day'
57
+ | 'pill'
58
+ | 'pills'
59
+ | 'avatar'
60
+ | 'avatars'
61
+ | 'empty'
62
+ | 'component'
45
63
 
46
64
  export interface TableCellBase {
47
65
  type: TableCellType
@@ -50,7 +68,7 @@ export interface TableCellBase {
50
68
  export interface TableCellText extends TableCellBase {
51
69
  type: 'text'
52
70
  icon?: any
53
- value?: string | ((value: any, record: any) => string)
71
+ value?: string | null | ((value: any, record: any) => string | null)
54
72
  link?(value: any, record: any): string
55
73
  color?: TableCellTextColor | ((value: any, record: any) => TableCellTextColor)
56
74
  iconColor?: TableCellTextColor | ((value: any, record: any) => TableCellTextColor)
@@ -68,14 +86,15 @@ export type TableCellTextColor =
68
86
 
69
87
  export interface TableCellDay extends TableCellBase {
70
88
  type: 'day'
89
+ value?: Day | null
71
90
  format?: string
72
91
  color?: 'neutral' | 'soft' | 'mute'
73
92
  }
74
93
 
75
94
  export interface TableCellPill extends TableCellBase {
76
95
  type: 'pill'
77
- value?: string | ((value: any) => string)
78
- color?: TableCellPillColor | ((value: any) => TableCellPillColor)
96
+ value?: string | ((value: any, record: any) => string)
97
+ color?: TableCellPillColor | ((value: any, record: any) => TableCellPillColor)
79
98
  }
80
99
 
81
100
  export type TableCellPillColor = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
@@ -92,33 +111,37 @@ export interface TableCellPillItem {
92
111
 
93
112
  export interface TableCellAvatar extends TableCellBase {
94
113
  type: 'avatar'
95
- image?(value: any, record: any): string | undefined
96
- name?(value: any, record: any): string
97
- link?(value: any, record: any): string
114
+ image?: string | null | ((value: any, record: any) => string | null | undefined)
115
+ name?: string | null | ((value: any, record: any) => string | null | undefined)
116
+ link?: string | null | ((value: any, record: any) => string | null | undefined)
98
117
  color?: 'neutral' | 'soft' | 'mute'
99
118
  }
100
119
 
101
120
  export interface TableCellAvatars extends TableCellBase {
102
121
  type: 'avatars'
103
- avatars(value: any, record: any): TableCellAvatarsOption[]
122
+ avatars: TableCellAvatarsOption[] | ((value: any, record: any) => TableCellAvatarsOption[])
104
123
  color?: 'neutral' | 'soft' | 'mute'
105
124
  }
106
125
 
126
+ export interface TableCellAvatarsOption {
127
+ image?: string | null
128
+ name?: string | null
129
+ }
130
+
131
+ export interface TableCellEmpty extends TableCellBase {
132
+ type: 'empty'
133
+ }
134
+
107
135
  export interface TableCellComponent extends TableCellBase {
108
136
  type: 'component'
109
137
  component: Component
110
138
  props?: Record<string, any>
111
139
  }
112
140
 
113
- export interface TableCellAvatarsOption {
114
- image?: string
115
- name?: string
116
- }
117
-
118
- export interface UseTableOptions {
119
- orders: MaybeRef<string[]>
120
- columns: MaybeRef<TableColumns>
121
- records?: MaybeRef<Record<string, any>[] | null | undefined>
141
+ export interface UseTableOptions<O extends string, R extends Record<string, any>> {
142
+ orders: MaybeRef<O[]>
143
+ columns: MaybeRef<TableColumns<O, R>>
144
+ records?: MaybeRef<R[] | null | undefined>
122
145
  header?: MaybeRef<boolean | undefined>
123
146
  footer?: MaybeRef<boolean | undefined>
124
147
  total?: MaybeRef<number | null | undefined>
@@ -132,6 +155,8 @@ export interface UseTableOptions {
132
155
  onReset?(): void
133
156
  }
134
157
 
135
- export function useTable(options: UseTableOptions): Table {
136
- return reactive(options)
158
+ export function useTable<O extends string, R extends Record<string, any>>(
159
+ options: UseTableOptions<O, R>
160
+ ): Table<O, R> {
161
+ return reactive(options) as Table<O, R>
137
162
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@globalbrain/sefirot",
3
- "version": "2.24.0",
3
+ "version": "2.26.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>",
@@ -39,7 +39,7 @@
39
39
  "postcss-nested": "^6.0.0",
40
40
  "typescript": "^4.9.4",
41
41
  "v-calendar": "^3.0.0-alpha.8",
42
- "vue": "^3.2.45",
42
+ "vue": "^3.2.47",
43
43
  "vue-router": "^4.1.6"
44
44
  },
45
45
  "dependencies": {
@@ -47,7 +47,7 @@
47
47
  },
48
48
  "devDependencies": {
49
49
  "@globalbrain/eslint-config": "^1.3.0",
50
- "@histoire/plugin-vue": "^0.12.4",
50
+ "@histoire/plugin-vue": "^0.15.8",
51
51
  "@iconify-icons/ph": "^1.2.3",
52
52
  "@iconify/vue": "^4.0.2",
53
53
  "@types/body-scroll-lock": "^3.1.0",
@@ -67,7 +67,7 @@
67
67
  "eslint": "^8.35.0",
68
68
  "execa": "^5.1.1",
69
69
  "fuse.js": "^6.6.2",
70
- "histoire": "^0.12.4",
70
+ "histoire": "^0.15.8",
71
71
  "lodash-es": "^4.17.21",
72
72
  "markdown-it": "^13.0.1",
73
73
  "normalize.css": "^8.0.1",
@@ -80,7 +80,7 @@
80
80
  "vite": "^4.1.4",
81
81
  "vitepress": "1.0.0-alpha.50",
82
82
  "vitest": "^0.29.2",
83
- "vue": "^3.2.45",
83
+ "vue": "^3.2.47",
84
84
  "vue-router": "^4.1.6",
85
85
  "vue-tsc": "^1.2.0"
86
86
  },