@globalbrain/sefirot 4.21.0 → 4.22.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.
@@ -124,10 +124,12 @@ function renderChart({
124
124
  .range(vertical ? [0, width] : [0, height])
125
125
  .padding(0.4)
126
126
 
127
- // Y scale for bar values
127
+ // Y scale for bar values, including negative values
128
+ const minValue = d3.min(props.data, (d) => d.value)!
129
+ const maxValue = d3.max(props.data, (d) => d.value)!
128
130
  const y = d3
129
131
  .scaleLinear()
130
- .domain([0, d3.max(props.data, (d) => d.value)!])
132
+ .domain([Math.min(0, minValue), Math.max(0, maxValue)])
131
133
  .nice()
132
134
  .range(vertical ? [height, 0] : [0, width])
133
135
 
@@ -137,6 +139,9 @@ function renderChart({
137
139
  const bandwidth = Math.min(paddedScale.bandwidth(), props.maxBandwidth)
138
140
  const innerOffset = (paddedScale.bandwidth() - bandwidth) / 2
139
141
 
142
+ // Baseline coordinate for zero value
143
+ const y0 = y(0)
144
+
140
145
  // For the axes, use the paddedScale so ticks remain centered on the bars.
141
146
  svg
142
147
  .append('g')
@@ -241,24 +246,24 @@ function renderChart({
241
246
  if (vertical) {
242
247
  outerBars
243
248
  .attr('x', 0)
244
- .attr('y', (d) => Math.max(0, y(d.value) - heightPadding))
249
+ .attr('y', (d) => Math.min(y(d.value), y0) - (d.value >= 0 ? heightPadding : 0))
245
250
  .attr('width', paddedScale.step())
246
- .attr('height', (d) => height - Math.max(0, y(d.value) - heightPadding))
251
+ .attr('height', (d) => Math.abs(y(d.value) - y0) + heightPadding)
247
252
  bars
248
253
  .attr('x', groupOffset + innerOffset)
249
- .attr('y', (d) => y(d.value))
254
+ .attr('y', (d) => (d.value >= 0 ? y(d.value) : y0))
250
255
  .attr('width', bandwidth)
251
- .attr('height', (d) => height - y(d.value))
256
+ .attr('height', (d) => Math.abs(y(d.value) - y0))
252
257
  } else {
253
258
  outerBars
254
- .attr('x', 0)
259
+ .attr('x', (d) => Math.min(y(d.value), y0) - (d.value >= 0 ? 0 : heightPadding))
255
260
  .attr('y', 0)
256
- .attr('width', (d) => Math.min(width, y(d.value) + heightPadding))
261
+ .attr('width', (d) => Math.abs(y(d.value) - y0) + heightPadding)
257
262
  .attr('height', paddedScale.step())
258
263
  bars
259
- .attr('x', 0)
264
+ .attr('x', (d) => (d.value >= 0 ? y0 : y(d.value)))
260
265
  .attr('y', groupOffset + innerOffset)
261
- .attr('width', (d) => y(d.value))
266
+ .attr('width', (d) => Math.abs(y(d.value) - y0))
262
267
  .attr('height', bandwidth)
263
268
  }
264
269
  } else {
@@ -266,43 +271,45 @@ function renderChart({
266
271
  if (vertical) {
267
272
  outerBars
268
273
  .attr('x', 0)
269
- .attr('y', height)
274
+ .attr('y', y0)
270
275
  .attr('width', paddedScale.step())
271
276
  .attr('height', 0)
272
277
  .transition()
273
278
  .duration(800)
274
279
  .delay((_, i) => i * 100)
275
- .attr('y', (d) => Math.max(0, y(d.value) - heightPadding))
276
- .attr('height', (d) => height - Math.max(0, y(d.value) - heightPadding))
280
+ .attr('y', (d) => Math.min(y(d.value), y0) - (d.value >= 0 ? heightPadding : 0))
281
+ .attr('height', (d) => Math.abs(y(d.value) - y0) + heightPadding)
277
282
  bars
278
283
  .attr('x', groupOffset + innerOffset)
279
- .attr('y', height)
284
+ .attr('y', y0)
280
285
  .attr('width', bandwidth)
281
286
  .attr('height', 0)
282
287
  .transition()
283
288
  .duration(800)
284
289
  .delay((_, i) => i * 100)
285
- .attr('y', (d) => y(d.value))
286
- .attr('height', (d) => height - y(d.value))
290
+ .attr('y', (d) => (d.value >= 0 ? y(d.value) : y0))
291
+ .attr('height', (d) => Math.abs(y(d.value) - y0))
287
292
  } else {
288
293
  outerBars
289
- .attr('x', 0)
294
+ .attr('x', y0)
290
295
  .attr('y', 0)
291
296
  .attr('width', 0)
292
297
  .attr('height', paddedScale.step())
293
298
  .transition()
294
299
  .duration(800)
295
300
  .delay((_, i) => i * 100)
296
- .attr('width', (d) => Math.min(width, y(d.value) + heightPadding))
301
+ .attr('x', (d) => Math.min(y(d.value), y0) - (d.value >= 0 ? 0 : heightPadding))
302
+ .attr('width', (d) => Math.abs(y(d.value) - y0) + heightPadding)
297
303
  bars
298
- .attr('x', 0)
304
+ .attr('x', y0)
299
305
  .attr('y', groupOffset + innerOffset)
300
306
  .attr('width', 0)
301
307
  .attr('height', bandwidth)
302
308
  .transition()
303
309
  .duration(800)
304
310
  .delay((_, i) => i * 100)
305
- .attr('width', (d) => y(d.value))
311
+ .attr('x', (d) => (d.value >= 0 ? y0 : y(d.value)))
312
+ .attr('width', (d) => Math.abs(y(d.value) - y0))
306
313
  }
307
314
  }
308
315
 
@@ -389,6 +396,7 @@ watch(
389
396
  position: absolute;
390
397
  top: 0;
391
398
  left: 0;
399
+ z-index: 1;
392
400
  padding: 2px 8px;
393
401
  background-color: var(--c-bg-elv-2);
394
402
  border: 1px solid var(--c-divider);
@@ -370,6 +370,7 @@ watch(
370
370
  position: absolute;
371
371
  top: 0;
372
372
  left: 0;
373
+ z-index: 1;
373
374
  padding: 2px 8px;
374
375
  background-color: var(--c-bg-elv-2);
375
376
  border: 1px solid var(--c-divider);
@@ -2,17 +2,23 @@
2
2
  import IconCaretDown from '~icons/ph/caret-down'
3
3
  import IconCaretUp from '~icons/ph/caret-up'
4
4
  import xor from 'lodash-es/xor'
5
- import { type Component, computed, ref } from 'vue'
5
+ import { computed, ref } from 'vue'
6
6
  import { type DropdownSectionFilter, useManualDropdownPosition } from '../composables/Dropdown'
7
7
  import { useFlyout } from '../composables/Flyout'
8
8
  import { useTrans } from '../composables/Lang'
9
- import { type Validatable } from '../composables/Validation'
10
9
  import SDropdown from './SDropdown.vue'
11
- import SInputBase from './SInputBase.vue'
10
+ import SInputBase, { type Props as BaseProps } from './SInputBase.vue'
12
11
  import SInputDropdownItem from './SInputDropdownItem.vue'
13
12
 
14
- export type Size = 'mini' | 'small' | 'medium'
15
- export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
13
+ export interface Props extends BaseProps {
14
+ placeholder?: string
15
+ options: Option[]
16
+ position?: 'top' | 'bottom'
17
+ noSearch?: boolean
18
+ nullable?: boolean
19
+ closeOnClick?: boolean
20
+ disabled?: boolean
21
+ }
16
22
 
17
23
  export type PrimitiveValue = any
18
24
  export type ArrayValue = any[]
@@ -37,24 +43,7 @@ export interface OptionAvatar extends OptionBase {
37
43
  image?: string | null
38
44
  }
39
45
 
40
- const props = defineProps<{
41
- size?: Size
42
- label?: string
43
- info?: string
44
- note?: string
45
- help?: string
46
- placeholder?: string
47
- checkIcon?: Component
48
- checkText?: string
49
- checkColor?: Color
50
- options: Option[]
51
- position?: 'top' | 'bottom'
52
- noSearch?: boolean
53
- nullable?: boolean
54
- closeOnClick?: boolean
55
- disabled?: boolean
56
- validation?: Validatable
57
- }>()
46
+ const props = defineProps<Props>()
58
47
 
59
48
  const model = defineModel<PrimitiveValue | ArrayValue>({ required: true })
60
49
 
@@ -143,6 +132,7 @@ function handleArray(value: OptionValue) {
143
132
  <SInputBase
144
133
  class="SInputDropdown"
145
134
  :class="classes"
135
+ :size
146
136
  :label
147
137
  :note
148
138
  :info
@@ -181,8 +171,10 @@ function handleArray(value: OptionValue) {
181
171
  </div>
182
172
  </div>
183
173
 
184
- <div v-if="isOpen" class="dropdown" :class="position">
185
- <SDropdown :sections="dropdownOptions" />
174
+ <div v-if="isOpen" class="dropdown" :class="props.position ?? position">
175
+ <div class="dropdown-content">
176
+ <SDropdown :sections="dropdownOptions" />
177
+ </div>
186
178
  </div>
187
179
  </div>
188
180
  <template v-if="$slots.info" #info><slot name="info" /></template>
@@ -248,8 +240,21 @@ function handleArray(value: OptionValue) {
248
240
  left: 0;
249
241
  z-index: var(--z-index-dropdown);
250
242
 
251
- &.top { bottom: calc(100% + 8px); }
252
- &.bottom { top: calc(100% + 8px); }
243
+ &.top {
244
+ bottom: calc(100% + 8px);
245
+
246
+ :deep(.SDropdown) {
247
+ transform: translateY(-100%);
248
+ }
249
+ }
250
+
251
+ &.bottom {
252
+ top: calc(100% + 8px);
253
+ }
254
+ }
255
+
256
+ .dropdown-content {
257
+ position: fixed;
253
258
  }
254
259
 
255
260
  .SInputDropdown.mini {
@@ -1,10 +1,16 @@
1
1
  <script setup lang="ts">
2
- import { type Component, computed, ref } from 'vue'
3
- import { type Validatable } from '../composables/Validation'
4
- import SInputBase from './SInputBase.vue'
2
+ import { computed, ref } from 'vue'
3
+ import SInputBase, { type Props as BaseProps } from './SInputBase.vue'
5
4
 
6
- export type Size = 'mini' | 'small' | 'medium'
7
- export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
5
+ export interface Props extends BaseProps {
6
+ placeholder?: Placeholder
7
+ noHour?: boolean
8
+ noMinute?: boolean
9
+ noSecond?: boolean
10
+ disabled?: boolean
11
+ value?: Value
12
+ modelValue?: Value
13
+ }
8
14
 
9
15
  export interface Value {
10
16
  hour: string | null
@@ -20,25 +26,7 @@ export interface Placeholder {
20
26
 
21
27
  export type ValueType = 'hour' | 'minute' | 'second'
22
28
 
23
- const props = defineProps<{
24
- size?: Size
25
- label?: string
26
- info?: string
27
- note?: string
28
- help?: string
29
- placeholder?: Placeholder
30
- checkIcon?: Component
31
- checkText?: string
32
- checkColor?: Color
33
- noHour?: boolean
34
- noMinute?: boolean
35
- noSecond?: boolean
36
- disabled?: boolean
37
- value?: Value
38
- modelValue?: Value
39
- validation?: Validatable
40
- hideError?: boolean
41
- }>()
29
+ const props = defineProps<Props>()
42
30
 
43
31
  const emit = defineEmits<{
44
32
  'update:model-value': [value: Value]
@@ -144,6 +132,7 @@ function createRequiredTouched(): boolean[] {
144
132
  <SInputBase
145
133
  class="SInputHMS"
146
134
  :class="[size ?? 'small', { disabled }]"
135
+ :size
147
136
  :label
148
137
  :note
149
138
  :info
@@ -1,10 +1,17 @@
1
1
  <script setup lang="ts">
2
- import { type Component, computed, ref } from 'vue'
3
- import { type Validatable } from '../composables/Validation'
4
- import SInputBase from './SInputBase.vue'
2
+ import { computed, ref } from 'vue'
3
+ import SInputBase, { type Props as BaseProps } from './SInputBase.vue'
5
4
 
6
- export type Size = 'mini' | 'small' | 'medium'
7
- export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
5
+ export interface Props extends BaseProps {
6
+ placeholder?: Placeholder
7
+ noYear?: boolean
8
+ noMonth?: boolean
9
+ noDate?: boolean
10
+ block?: boolean
11
+ disabled?: boolean
12
+ value?: Value
13
+ modelValue?: Value
14
+ }
8
15
 
9
16
  export interface Value {
10
17
  year: number | null
@@ -20,26 +27,7 @@ export interface Placeholder {
20
27
  date?: number
21
28
  }
22
29
 
23
- const props = defineProps<{
24
- size?: Size
25
- label?: string
26
- info?: string
27
- note?: string
28
- help?: string
29
- placeholder?: Placeholder
30
- checkIcon?: Component
31
- checkText?: string
32
- checkColor?: Color
33
- noYear?: boolean
34
- noMonth?: boolean
35
- noDate?: boolean
36
- block?: boolean
37
- disabled?: boolean
38
- value?: Value
39
- modelValue?: Value
40
- validation?: Validatable
41
- hideError?: boolean
42
- }>()
30
+ const props = defineProps<Props>()
43
31
 
44
32
  const emit = defineEmits<{
45
33
  'update:model-value': [value: Value]
@@ -143,6 +131,7 @@ function createRequiredTouched(): boolean[] {
143
131
  <SInputBase
144
132
  class="SInputYMD"
145
133
  :class="[size ?? 'small', { disabled }]"
134
+ :size
146
135
  :label
147
136
  :note
148
137
  :info
@@ -51,6 +51,7 @@
51
51
  .s-gap-8 { gap: 8px; }
52
52
  .s-gap-12 { gap: 12px; }
53
53
  .s-gap-16 { gap: 16px; }
54
+ .s-gap-24 { gap: 24px; }
54
55
 
55
56
  .s-order-1 { order: 1; }
56
57
  .s-order-2 { order: 2; }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@globalbrain/sefirot",
3
3
  "type": "module",
4
- "version": "4.21.0",
4
+ "version": "4.22.0",
5
5
  "packageManager": "pnpm@9.15.4",
6
6
  "description": "Vue Components for Global Brain Design System.",
7
7
  "author": "Kia Ishii <ka.ishii@globalbrains.com>",