@youcan/celeste 0.11.0 → 0.13.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 (116) hide show
  1. package/ai/component-registry.json +30 -2
  2. package/ai/component-registry.md +5 -1
  3. package/ai/icons.md +1 -1
  4. package/ai/tokens.md +1 -1
  5. package/dist/celeste.css +311 -218
  6. package/dist/cjs/chunks/ConfigProvider.cjs +58 -1
  7. package/dist/cjs/chunks/calendar.cjs +73 -67
  8. package/dist/cjs/chunks/combobox-root.cjs +12 -5
  9. package/dist/cjs/chunks/digit-input.cjs +13 -7
  10. package/dist/cjs/chunks/dist2.cjs +6 -0
  11. package/dist/cjs/chunks/dropdown-menu.cjs +10 -4
  12. package/dist/cjs/chunks/fancy-button.cjs +1 -1
  13. package/dist/cjs/chunks/radio-group.cjs +9 -3
  14. package/dist/cjs/chunks/range-calendar.cjs +73 -67
  15. package/dist/cjs/chunks/scroll-area.cjs +18 -12
  16. package/dist/cjs/chunks/scroll-bar.cjs +2 -0
  17. package/dist/cjs/chunks/segmented-control-item.cjs +1 -1
  18. package/dist/cjs/chunks/segmented-control.cjs +25 -4
  19. package/dist/cjs/chunks/select.cjs +9 -3
  20. package/dist/cjs/chunks/slider.cjs +16 -10
  21. package/dist/cjs/chunks/tab-menu-item.cjs +6 -2
  22. package/dist/cjs/chunks/tab-menu-list.cjs +53 -9
  23. package/dist/cjs/chunks/tab-menu.cjs +12 -5
  24. package/dist/cjs/chunks/text-input.cjs +1 -1
  25. package/dist/cjs/command-root.cjs +9 -3
  26. package/dist/cjs/index.cjs +4 -0
  27. package/dist/cjs/use-direction.cjs +31 -0
  28. package/dist/cjs/use-tab-observer.cjs +42 -0
  29. package/dist/components/combobox/combobox-root.d.ts +2 -2
  30. package/dist/components/dropdown-menu/dropdown-menu.d.ts +2 -2
  31. package/dist/components/radio-group/radio-group.d.ts +2 -2
  32. package/dist/components/scroll-area/scroll-area.d.ts +2 -2
  33. package/dist/components/segmented-control/segmented-control.d.ts +2 -2
  34. package/dist/components/select/select.d.ts +2 -2
  35. package/dist/components/tab-menu/tab-menu-list.d.ts +14 -5
  36. package/dist/components/tab-menu/tab-menu.d.ts +2 -2
  37. package/dist/composables/index.d.ts +2 -0
  38. package/dist/composables/use-direction.d.ts +3 -0
  39. package/dist/composables/use-tab-observer.d.ts +14 -0
  40. package/dist/es/chunks/BubbleSelect.js +1 -1
  41. package/dist/es/chunks/CollapsibleRoot.js +1 -1
  42. package/dist/es/chunks/ComboboxInput.js +1 -1
  43. package/dist/es/chunks/ComboboxRoot.js +1 -1
  44. package/dist/es/chunks/ConfigProvider.js +53 -2
  45. package/dist/es/chunks/DialogRoot.js +1 -1
  46. package/dist/es/chunks/DropdownMenuRoot.js +1 -1
  47. package/dist/es/chunks/FocusScope.js +1 -1
  48. package/dist/es/chunks/MenuRoot.js +1 -1
  49. package/dist/es/chunks/MenuSub.js +1 -1
  50. package/dist/es/chunks/PaginationRoot.js +1 -1
  51. package/dist/es/chunks/PinInputRoot.js +1 -1
  52. package/dist/es/chunks/PopoverRoot.js +1 -1
  53. package/dist/es/chunks/ProgressIndicator.js +1 -1
  54. package/dist/es/chunks/RadioGroupRoot.js +1 -1
  55. package/dist/es/chunks/RovingFocusGroup.js +1 -1
  56. package/dist/es/chunks/SelectItemAlignedPosition.js +1 -1
  57. package/dist/es/chunks/TabsRoot.js +1 -1
  58. package/dist/es/chunks/Teleport.js +1 -1
  59. package/dist/es/chunks/ToggleGroupRoot.js +1 -1
  60. package/dist/es/chunks/TooltipRoot.js +1 -1
  61. package/dist/es/chunks/bar-chart.js +1 -1
  62. package/dist/es/chunks/calendar.js +74 -68
  63. package/dist/es/chunks/checkbox.js +1 -1
  64. package/dist/es/chunks/combobox-root.js +13 -6
  65. package/dist/es/chunks/counter-input.js +1 -1
  66. package/dist/es/chunks/digit-input.js +14 -8
  67. package/dist/es/chunks/dist2.js +1 -1
  68. package/dist/es/chunks/dropdown-menu-sub.js +1 -1
  69. package/dist/es/chunks/dropdown-menu.js +11 -5
  70. package/dist/es/chunks/fancy-button.js +1 -1
  71. package/dist/es/chunks/radio-group-item.js +1 -1
  72. package/dist/es/chunks/radio-group.js +10 -4
  73. package/dist/es/chunks/range-calendar.js +74 -68
  74. package/dist/es/chunks/scroll-area.js +19 -13
  75. package/dist/es/chunks/scroll-bar.js +3 -1
  76. package/dist/es/chunks/segmented-control-item.js +2 -2
  77. package/dist/es/chunks/segmented-control.js +27 -5
  78. package/dist/es/chunks/select.js +10 -4
  79. package/dist/es/chunks/sidebar-provider.js +1 -1
  80. package/dist/es/chunks/slider.js +17 -11
  81. package/dist/es/chunks/switch.js +1 -1
  82. package/dist/es/chunks/tab-menu-item.js +6 -2
  83. package/dist/es/chunks/tab-menu-list.js +56 -10
  84. package/dist/es/chunks/tab-menu.js +13 -6
  85. package/dist/es/chunks/text-input.js +1 -1
  86. package/dist/es/chunks/useDirection.js +1 -1
  87. package/dist/es/chunks/useId.js +1 -1
  88. package/dist/es/chunks/useLocale.js +1 -1
  89. package/dist/es/chunks/useNonce.js +1 -1
  90. package/dist/es/command-root.js +10 -4
  91. package/dist/es/index.js +3 -1
  92. package/dist/es/use-direction.js +30 -0
  93. package/dist/es/use-tab-observer.js +41 -0
  94. package/package.json +3 -3
  95. package/src/components/button/fancy-button.vue +14 -4
  96. package/src/components/calendar/calendar.vue +66 -60
  97. package/src/components/combobox/combobox-root.vue +9 -4
  98. package/src/components/command/command-root.vue +13 -8
  99. package/src/components/digit-input/digit-input.vue +13 -8
  100. package/src/components/dropdown-menu/dropdown-menu.vue +12 -7
  101. package/src/components/radio-group/radio-group.vue +12 -7
  102. package/src/components/range-calendar/range-calendar.vue +67 -61
  103. package/src/components/scroll-area/scroll-area.vue +17 -18
  104. package/src/components/segmented-control/segmented-control-item.vue +3 -3
  105. package/src/components/segmented-control/segmented-control.vue +48 -8
  106. package/src/components/select/select.vue +12 -7
  107. package/src/components/slider/slider.vue +19 -14
  108. package/src/components/switch/switch.vue +19 -18
  109. package/src/components/tab-menu/stories/tab-menu.stories.ts +39 -0
  110. package/src/components/tab-menu/tab-menu-item.vue +27 -28
  111. package/src/components/tab-menu/tab-menu-list.vue +85 -3
  112. package/src/components/tab-menu/tab-menu.vue +12 -4
  113. package/src/components/text-input/text-input.vue +11 -29
  114. package/src/composables/index.ts +2 -0
  115. package/src/composables/use-direction.ts +40 -0
  116. package/src/composables/use-tab-observer.ts +50 -0
@@ -4,20 +4,50 @@ import type { HTMLAttributes } from 'vue';
4
4
  import clsx from 'clsx';
5
5
  import { TabsList } from 'reka-ui';
6
6
  import { useDelegatedProps } from '@/composables/use-delegated-props';
7
+ import { useTabObserver } from '@/composables/use-tab-observer';
7
8
 
8
- const props = defineProps<TabsListProps & { class?: HTMLAttributes['class'] }>();
9
- const delegatedProps = useDelegatedProps(props, 'class');
9
+ export interface TabMenuListProps extends TabsListProps {
10
+ class?: HTMLAttributes['class'];
11
+ bordered?: boolean;
12
+ scrollable?: boolean;
13
+ fill?: boolean;
14
+ align?: 'start' | 'center';
15
+ }
16
+
17
+ const props = withDefaults(defineProps<TabMenuListProps>(), {
18
+ bordered: true,
19
+ scrollable: false,
20
+ fill: false,
21
+ align: 'start',
22
+ });
23
+
24
+ const delegatedProps = useDelegatedProps(props, ['class', 'bordered', 'scrollable', 'fill', 'align']);
25
+
26
+ const { listRef, indicator, ready } = useTabObserver('[data-state="active"]');
10
27
  </script>
11
28
 
12
29
  <template>
13
30
  <TabsList
31
+ ref="listRef"
14
32
  v-bind="delegatedProps"
33
+ :data-bordered="bordered"
34
+ :data-scrollable="scrollable"
35
+ :data-fill="fill"
36
+ :data-align="align"
15
37
  :class="clsx(
16
38
  'celeste-tab-menu-list',
17
39
  props.class,
18
40
  )"
19
41
  >
20
42
  <slot />
43
+ <div
44
+ :hidden="!ready"
45
+ class="celeste-tab-menu-indicator"
46
+ :style="{
47
+ width: `${indicator.width}px`,
48
+ transform: `translate3d(${indicator.left}px, 0, 0)`,
49
+ }"
50
+ />
21
51
  </TabsList>
22
52
  </template>
23
53
 
@@ -31,14 +61,66 @@ const delegatedProps = useDelegatedProps(props, 'class');
31
61
  gap: var(--spacing-8);
32
62
 
33
63
  &[data-orientation='horizontal'] {
64
+ position: relative;
34
65
  flex-direction: row;
35
66
  padding: var(--spacing-0);
36
- border-block: 1px solid var(--color-stroke-soft-200);
37
67
  gap: 24px;
68
+
69
+ &[data-bordered='true'] {
70
+ border-block: 1px solid var(--color-stroke-soft-200);
71
+ }
38
72
  }
39
73
 
40
74
  &[data-orientation='vertical'] {
41
75
  flex-direction: column;
42
76
  }
77
+
78
+ &[data-scrollable='true'] {
79
+ overflow-x: auto;
80
+ scrollbar-width: none;
81
+
82
+ &::-webkit-scrollbar {
83
+ display: none;
84
+ }
85
+ }
86
+
87
+ &[data-fill='true'] :deep(.celeste-tab-menu-item) {
88
+ flex: 1 1 0;
89
+ width: auto;
90
+ }
91
+
92
+ &[data-align='center'] :deep(.celeste-tab-menu-item) {
93
+ justify-content: center;
94
+ }
95
+
96
+ &[data-align='center'] :deep(.celeste-tab-menu-item-label) {
97
+ flex: 0 1 auto;
98
+ }
99
+ }
100
+
101
+ .celeste-tab-menu-indicator {
102
+ position: absolute;
103
+ bottom: -1px;
104
+ left: 0;
105
+ height: 2px;
106
+ transition-property: transform, width;
107
+ transition-duration: var(--animation-normal);
108
+ transition-timing-function: cubic-bezier(0.65, 0, 0.35, 1);
109
+ background-color: var(--color-primary-base);
110
+ pointer-events: none;
111
+
112
+ .celeste-tab-menu-list[data-scrollable='true'] > & {
113
+ bottom: 0;
114
+ }
115
+
116
+ .celeste-tab-menu-list[data-orientation='vertical'] > & {
117
+ display: none;
118
+ }
119
+ }
120
+
121
+ @media (prefers-reduced-motion: reduce) {
122
+ .celeste-tab-menu-indicator {
123
+ transition-duration: 0s;
124
+ }
43
125
  }
44
126
  </style>
@@ -1,17 +1,25 @@
1
1
  <script setup lang="ts">
2
2
  import type { TabsRootEmits, TabsRootProps } from 'reka-ui';
3
- import { TabsRoot, useForwardPropsEmits } from 'reka-ui';
3
+ import { ConfigProvider, TabsRoot, useForwardPropsEmits } from 'reka-ui';
4
+ import { useDirection } from '@/composables/use-direction';
4
5
 
5
6
  const props = defineProps<TabsRootProps>();
6
7
  const emits = defineEmits<TabsRootEmits>();
7
8
 
8
9
  const forwarded = useForwardPropsEmits(props, emits);
10
+
11
+ const direction = useDirection();
9
12
  </script>
10
13
 
11
14
  <template>
12
- <TabsRoot v-bind="forwarded" class="celeste-tab-menu-root">
13
- <slot />
14
- </TabsRoot>
15
+ <ConfigProvider :dir="props.dir ?? direction">
16
+ <TabsRoot
17
+ v-bind="forwarded"
18
+ class="celeste-tab-menu-root"
19
+ >
20
+ <slot />
21
+ </TabsRoot>
22
+ </ConfigProvider>
15
23
  </template>
16
24
 
17
25
  <style scoped>
@@ -270,41 +270,23 @@ function clearInput() {
270
270
 
271
271
  :deep(.celeste-text-input-node.celeste-text-input-leading-node),
272
272
  :deep(.celeste-text-input-node.celeste-text-input-trailing-node) {
273
- height: calc(var(--input-height) - var(--spacing-2)) !important;
274
- }
275
-
276
- [dir='ltr'] & {
277
- :deep(.celeste-text-input-node.celeste-text-input-leading-node) {
278
- border-right: 1px solid var(--color-stroke-soft-200) !important;
279
- border-radius: var(--input-radius) 0 0 var(--input-radius) !important;
280
- }
281
-
282
- :deep(.celeste-text-input-node.celeste-text-input-trailing-node) {
283
- border-left: 1px solid var(--color-stroke-soft-200) !important;
284
- border-radius: 0 var(--input-radius) var(--input-radius) 0 !important;
285
- }
286
- }
287
-
288
- [dir='rtl'] & {
289
- :deep(.celeste-text-input-node.celeste-text-input-leading-node) {
290
- border-left: 1px solid var(--color-stroke-soft-200) !important;
291
- border-radius: 0 var(--input-radius) var(--input-radius) 0 !important;
292
- }
293
-
294
- :deep(.celeste-text-input-node.celeste-text-input-trailing-node) {
295
- border-right: 1px solid var(--color-stroke-soft-200) !important;
296
- border-radius: var(--input-radius) 0 0 var(--input-radius) !important;
297
- }
273
+ height: calc(var(--input-height) - var(--spacing-2));
298
274
  }
299
275
 
300
276
  :deep(.celeste-text-input-node.celeste-text-input-leading-node) {
301
- border-right: 1px solid var(--color-stroke-soft-200) !important;
302
- border-radius: var(--input-radius) 0 0 var(--input-radius) !important;
277
+ border-inline-end: 1px solid var(--color-stroke-soft-200);
278
+ border-start-start-radius: var(--input-radius);
279
+ border-start-end-radius: 0;
280
+ border-end-end-radius: 0;
281
+ border-end-start-radius: var(--input-radius);
303
282
  }
304
283
 
305
284
  :deep(.celeste-text-input-node.celeste-text-input-trailing-node) {
306
- border-left: 1px solid var(--color-stroke-soft-200) !important;
307
- border-radius: 0 var(--input-radius) var(--input-radius) 0 !important;
285
+ border-inline-start: 1px solid var(--color-stroke-soft-200);
286
+ border-start-start-radius: 0;
287
+ border-start-end-radius: var(--input-radius);
288
+ border-end-end-radius: var(--input-radius);
289
+ border-end-start-radius: 0;
308
290
  }
309
291
  }
310
292
  </style>
@@ -1,4 +1,6 @@
1
1
  export * from './use-chart-motion';
2
2
  export * from './use-delegated-props';
3
+ export * from './use-direction';
3
4
  export * from './use-locale';
4
5
  export * from './use-sidebar';
6
+ export * from './use-tab-observer';
@@ -0,0 +1,40 @@
1
+ import type { Direction } from 'reka-ui';
2
+ import type { Ref } from 'vue';
3
+ import { getCurrentInstance, onMounted, ref, watch } from 'vue';
4
+
5
+ const revision = ref(0);
6
+
7
+ let observer: MutationObserver | undefined;
8
+
9
+ function observeDocument(): void {
10
+ if (observer || typeof document === 'undefined')
11
+ return;
12
+
13
+ observer = new MutationObserver(() => revision.value++);
14
+ observer.observe(document.documentElement, { attributeFilter: ['dir'], subtree: true });
15
+ }
16
+
17
+ function documentDirection(): Direction {
18
+ return typeof document !== 'undefined' && document.documentElement.dir === 'rtl' ? 'rtl' : 'ltr';
19
+ }
20
+
21
+ export function useDirection(): Ref<Direction> {
22
+ const instance = getCurrentInstance();
23
+ const direction = ref<Direction>(documentDirection());
24
+
25
+ observeDocument();
26
+
27
+ function read(): void {
28
+ const node = instance?.vnode.el as Node | null | undefined;
29
+ const element = node instanceof HTMLElement ? node : node?.parentElement;
30
+
31
+ direction.value = element
32
+ ? getComputedStyle(element).direction === 'rtl' ? 'rtl' : 'ltr'
33
+ : documentDirection();
34
+ }
35
+
36
+ onMounted(read);
37
+ watch(revision, read);
38
+
39
+ return direction;
40
+ }
@@ -0,0 +1,50 @@
1
+ import type { MaybeElement } from '@vueuse/core';
2
+ import type { Ref } from 'vue';
3
+ import { unrefElement, useMutationObserver, useResizeObserver } from '@vueuse/core';
4
+ import { ref, shallowRef } from 'vue';
5
+
6
+ export interface TabIndicator {
7
+ left: number;
8
+ top: number;
9
+ width: number;
10
+ height: number;
11
+ }
12
+
13
+ export interface TabObserver {
14
+ listRef: Ref<MaybeElement>;
15
+ indicator: Ref<TabIndicator>;
16
+ ready: Ref<boolean>;
17
+ }
18
+
19
+ export function useTabObserver(activeSelector: string): TabObserver {
20
+ const listRef = shallowRef<MaybeElement>(null);
21
+ const indicator = ref<TabIndicator>({ left: 0, top: 0, width: 0, height: 0 });
22
+ const ready = ref(false);
23
+
24
+ function update(): void {
25
+ const active = unrefElement(listRef)?.querySelector<HTMLElement>(activeSelector);
26
+ if (!active) {
27
+ ready.value = false;
28
+ return;
29
+ }
30
+
31
+ indicator.value = {
32
+ left: active.offsetLeft,
33
+ top: active.offsetTop,
34
+ width: active.offsetWidth,
35
+ height: active.offsetHeight,
36
+ };
37
+
38
+ ready.value = true;
39
+ }
40
+
41
+ useResizeObserver(listRef, update);
42
+ useMutationObserver(listRef, update, {
43
+ childList: true,
44
+ subtree: true,
45
+ attributes: true,
46
+ attributeFilter: ['data-state'],
47
+ });
48
+
49
+ return { listRef, indicator, ready };
50
+ }