@celestia-island/hikari 0.4.4

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 (187) hide show
  1. package/README.md +54 -0
  2. package/package.json +63 -0
  3. package/src/DemoApp.vue +400 -0
  4. package/src/components/HkActionBar.tsx +15 -0
  5. package/src/components/HkAlert.scss +121 -0
  6. package/src/components/HkAlert.tsx +85 -0
  7. package/src/components/HkAvatar.tsx +29 -0
  8. package/src/components/HkBadge.scss +117 -0
  9. package/src/components/HkBadge.tsx +50 -0
  10. package/src/components/HkBreadcrumb.tsx +39 -0
  11. package/src/components/HkButton.scss +128 -0
  12. package/src/components/HkButton.tsx +74 -0
  13. package/src/components/HkCard.scss +49 -0
  14. package/src/components/HkCard.tsx +38 -0
  15. package/src/components/HkCheckbox.scss +102 -0
  16. package/src/components/HkCheckbox.tsx +85 -0
  17. package/src/components/HkCollapse.tsx +48 -0
  18. package/src/components/HkColorPicker.scss +148 -0
  19. package/src/components/HkColorPicker.tsx +204 -0
  20. package/src/components/HkConfirmDialog.scss +12 -0
  21. package/src/components/HkConfirmDialog.tsx +75 -0
  22. package/src/components/HkDateTimePicker.scss +361 -0
  23. package/src/components/HkDateTimePicker.tsx +424 -0
  24. package/src/components/HkDivider.scss +85 -0
  25. package/src/components/HkDivider.tsx +51 -0
  26. package/src/components/HkDraggableGrid.scss +132 -0
  27. package/src/components/HkDraggableGrid.tsx +291 -0
  28. package/src/components/HkDraggableList.scss +110 -0
  29. package/src/components/HkDraggableList.tsx +238 -0
  30. package/src/components/HkDrawer.scss +175 -0
  31. package/src/components/HkDrawer.tsx +171 -0
  32. package/src/components/HkEmptyState.scss +42 -0
  33. package/src/components/HkEmptyState.tsx +41 -0
  34. package/src/components/HkErrorBoundary.scss +64 -0
  35. package/src/components/HkErrorBoundary.tsx +82 -0
  36. package/src/components/HkGaugeRing.scss +4 -0
  37. package/src/components/HkGaugeRing.tsx +130 -0
  38. package/src/components/HkHoverRevealAction.scss +66 -0
  39. package/src/components/HkHoverRevealAction.tsx +77 -0
  40. package/src/components/HkIcon.tsx +43 -0
  41. package/src/components/HkIconButton.tsx +42 -0
  42. package/src/components/HkImageViewer.scss +33 -0
  43. package/src/components/HkImageViewer.tsx +250 -0
  44. package/src/components/HkInput.scss +172 -0
  45. package/src/components/HkInput.tsx +175 -0
  46. package/src/components/HkKbd.tsx +26 -0
  47. package/src/components/HkKeywordSearchModal.scss +148 -0
  48. package/src/components/HkKeywordSearchModal.tsx +308 -0
  49. package/src/components/HkListTransition.scss +131 -0
  50. package/src/components/HkListTransition.tsx +29 -0
  51. package/src/components/HkLocalePickerPopup.tsx +42 -0
  52. package/src/components/HkLogo.scss +36 -0
  53. package/src/components/HkLogo.tsx +93 -0
  54. package/src/components/HkMarkdownRenderer.scss +141 -0
  55. package/src/components/HkMarkdownRenderer.tsx +123 -0
  56. package/src/components/HkMediaControlBar.scss +65 -0
  57. package/src/components/HkMediaControlBar.tsx +115 -0
  58. package/src/components/HkMediaPlayer.scss +29 -0
  59. package/src/components/HkMediaPlayer.tsx +210 -0
  60. package/src/components/HkMediaSlider.scss +54 -0
  61. package/src/components/HkMediaSlider.tsx +81 -0
  62. package/src/components/HkMediaVisualizer.scss +7 -0
  63. package/src/components/HkMediaVisualizer.tsx +119 -0
  64. package/src/components/HkMinimap.scss +76 -0
  65. package/src/components/HkMinimap.tsx +255 -0
  66. package/src/components/HkModal.scss +318 -0
  67. package/src/components/HkModal.tsx +481 -0
  68. package/src/components/HkModalBreadcrumb.scss +55 -0
  69. package/src/components/HkModalBreadcrumb.tsx +113 -0
  70. package/src/components/HkMorphingTabs.scss +141 -0
  71. package/src/components/HkMorphingTabs.tsx +113 -0
  72. package/src/components/HkNavItem.scss +81 -0
  73. package/src/components/HkNavItem.tsx +157 -0
  74. package/src/components/HkNumberInput.scss +154 -0
  75. package/src/components/HkNumberInput.tsx +161 -0
  76. package/src/components/HkPasswordInput.scss +289 -0
  77. package/src/components/HkPasswordInput.tsx +533 -0
  78. package/src/components/HkPhaseTransition.scss +25 -0
  79. package/src/components/HkPhaseTransition.tsx +40 -0
  80. package/src/components/HkPopover.scss +82 -0
  81. package/src/components/HkPopover.tsx +410 -0
  82. package/src/components/HkPopupSelect.scss +136 -0
  83. package/src/components/HkPopupSelect.tsx +199 -0
  84. package/src/components/HkProgressBar.scss +106 -0
  85. package/src/components/HkProgressBar.tsx +61 -0
  86. package/src/components/HkProgressDialog.tsx +67 -0
  87. package/src/components/HkProgressRing.scss +56 -0
  88. package/src/components/HkProgressRing.tsx +82 -0
  89. package/src/components/HkRadio.scss +119 -0
  90. package/src/components/HkRadio.tsx +75 -0
  91. package/src/components/HkRollingNumber.scss +37 -0
  92. package/src/components/HkRollingNumber.tsx +97 -0
  93. package/src/components/HkScrollContainer.scss +101 -0
  94. package/src/components/HkScrollContainer.tsx +362 -0
  95. package/src/components/HkSearchInput.scss +132 -0
  96. package/src/components/HkSearchInput.tsx +117 -0
  97. package/src/components/HkSelect.scss +143 -0
  98. package/src/components/HkSelect.tsx +230 -0
  99. package/src/components/HkSelectionGrid.scss +177 -0
  100. package/src/components/HkSelectionGrid.tsx +99 -0
  101. package/src/components/HkSelectionWaterfall.scss +93 -0
  102. package/src/components/HkSelectionWaterfall.tsx +90 -0
  103. package/src/components/HkSidebar.scss +81 -0
  104. package/src/components/HkSidebar.tsx +45 -0
  105. package/src/components/HkSkeleton.scss +44 -0
  106. package/src/components/HkSkeleton.tsx +30 -0
  107. package/src/components/HkSkeletonList.tsx +35 -0
  108. package/src/components/HkSpinner.scss +67 -0
  109. package/src/components/HkSpinner.tsx +41 -0
  110. package/src/components/HkSplash.scss +60 -0
  111. package/src/components/HkSplash.tsx +40 -0
  112. package/src/components/HkSwitch.scss +157 -0
  113. package/src/components/HkSwitch.tsx +72 -0
  114. package/src/components/HkTable.scss +198 -0
  115. package/src/components/HkTable.tsx +246 -0
  116. package/src/components/HkTabs.scss +109 -0
  117. package/src/components/HkTabs.tsx +111 -0
  118. package/src/components/HkTag.scss +88 -0
  119. package/src/components/HkTag.tsx +44 -0
  120. package/src/components/HkTextarea.scss +72 -0
  121. package/src/components/HkTextarea.tsx +104 -0
  122. package/src/components/HkTimeline.scss +139 -0
  123. package/src/components/HkTimeline.tsx +95 -0
  124. package/src/components/HkToast.scss +168 -0
  125. package/src/components/HkToast.tsx +175 -0
  126. package/src/components/HkTooltip.scss +47 -0
  127. package/src/components/HkTooltip.tsx +108 -0
  128. package/src/components/HkTree.scss +188 -0
  129. package/src/components/HkTree.tsx +217 -0
  130. package/src/components/HkTrendChart.tsx +180 -0
  131. package/src/components/HkWindowedItem.scss +17 -0
  132. package/src/components/HkWindowedItem.tsx +107 -0
  133. package/src/components/HkZoomToolbar.scss +35 -0
  134. package/src/components/HkZoomToolbar.tsx +69 -0
  135. package/src/composables/useBreakpoint.ts +41 -0
  136. package/src/composables/useClipboard.ts +37 -0
  137. package/src/composables/useConfirm.ts +35 -0
  138. package/src/composables/useProgressDialog.ts +52 -0
  139. package/src/composables/useReportedTransition.ts +69 -0
  140. package/src/composables/useScrollWindow.ts +21 -0
  141. package/src/composables/useToast.ts +2 -0
  142. package/src/demo.scss +24 -0
  143. package/src/demo.ts +22 -0
  144. package/src/env.d.ts +6 -0
  145. package/src/i18n/context.ts +89 -0
  146. package/src/i18n/locales/ar/components.json +43 -0
  147. package/src/i18n/locales/ar/components.toml +40 -0
  148. package/src/i18n/locales/de/components.json +43 -0
  149. package/src/i18n/locales/de/components.toml +40 -0
  150. package/src/i18n/locales/en/components.json +43 -0
  151. package/src/i18n/locales/en/components.toml +40 -0
  152. package/src/i18n/locales/es/components.json +43 -0
  153. package/src/i18n/locales/es/components.toml +40 -0
  154. package/src/i18n/locales/fr/components.json +43 -0
  155. package/src/i18n/locales/fr/components.toml +40 -0
  156. package/src/i18n/locales/ja/components.json +43 -0
  157. package/src/i18n/locales/ja/components.toml +40 -0
  158. package/src/i18n/locales/ko/components.json +43 -0
  159. package/src/i18n/locales/ko/components.toml +40 -0
  160. package/src/i18n/locales/pt/components.json +43 -0
  161. package/src/i18n/locales/pt/components.toml +40 -0
  162. package/src/i18n/locales/ru/components.json +43 -0
  163. package/src/i18n/locales/ru/components.toml +40 -0
  164. package/src/i18n/locales/zh-Hans/components.json +43 -0
  165. package/src/i18n/locales/zh-Hans/components.toml +40 -0
  166. package/src/i18n/locales/zh-Hant/components.json +43 -0
  167. package/src/i18n/locales/zh-Hant/components.toml +40 -0
  168. package/src/index.ts +137 -0
  169. package/src/render.ts +18 -0
  170. package/src/runtime/animationBus.ts +278 -0
  171. package/src/runtime/cronBus.ts +25 -0
  172. package/src/runtime/index.ts +12 -0
  173. package/src/runtime/useAsyncData.ts +30 -0
  174. package/src/runtime/useBreakpoint.ts +62 -0
  175. package/src/runtime/useClipboard.ts +37 -0
  176. package/src/runtime/useConfirm.ts +35 -0
  177. package/src/runtime/useOverlay.ts +82 -0
  178. package/src/runtime/usePopupManager.ts +89 -0
  179. package/src/runtime/useToast.ts +140 -0
  180. package/src/styles/index.scss +10 -0
  181. package/src/theme/index.ts +5 -0
  182. package/src/theme/presets.ts +307 -0
  183. package/src/theme/theme.scss +17 -0
  184. package/src/theme/useBackgroundLuminance.ts +145 -0
  185. package/src/theme/useSolarTime.ts +101 -0
  186. package/src/theme/useTheme.ts +141 -0
  187. package/src/tokens.scss +26 -0
@@ -0,0 +1,141 @@
1
+ .hk-morphing-tabs {
2
+ display: flex;
3
+ flex-direction: column;
4
+ height: 100%;
5
+ width: 100%;
6
+ }
7
+
8
+ .hk-morphing-tabs-header {
9
+ display: flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+ flex-shrink: 0;
13
+ }
14
+
15
+ .hk-morphing-tabs-triggers {
16
+ position: relative;
17
+ display: inline-flex;
18
+ align-items: center;
19
+ gap: 0;
20
+ border-radius: var(--hi-radius-sm, 4px);
21
+ border: 1px solid color-mix(in srgb, var(--hi-color-border) 12%, transparent);
22
+ padding: 2px;
23
+ background: color-mix(in srgb, var(--hi-color-surface) 60%, transparent);
24
+ }
25
+
26
+ .hk-morphing-tabs-indicator {
27
+ position: absolute;
28
+ top: 2px;
29
+ left: 2px;
30
+ height: calc(100% - 4px);
31
+ width: calc((100% - 4px) / var(--tab-count, 1));
32
+ border-radius: var(--hi-radius-sm, 4px);
33
+ background: color-mix(in srgb, var(--hi-color-primary) 12%, transparent);
34
+ box-shadow: 0 1px 3px rgb(0 0 0 / 8%);
35
+ pointer-events: none;
36
+ z-index: 0;
37
+ transform: translateX(calc(var(--tab-index, 0) * 100%));
38
+ transition: transform var(--hi-duration-normal, 0.3s) ease;
39
+ }
40
+
41
+ .hk-morphing-tabs-trigger {
42
+ position: relative;
43
+ z-index: 1;
44
+ flex: 1 1 0;
45
+ padding: 4px 14px;
46
+ font-size: var(--hi-text-sm, 0.875rem);
47
+ font-weight: 600;
48
+ border-radius: var(--hi-radius-sm, 4px);
49
+ border: none;
50
+ background: transparent;
51
+ color: var(--hi-color-muted);
52
+ cursor: pointer;
53
+ white-space: nowrap;
54
+ transition: color var(--hi-duration-normal, 0.3s) ease;
55
+
56
+ &:hover:not(:disabled) {
57
+ color: var(--hi-color-text-primary);
58
+ }
59
+
60
+ &:disabled {
61
+ opacity: 0.4;
62
+ cursor: not-allowed;
63
+ }
64
+ }
65
+
66
+ .hk-morphing-tabs-trigger-active {
67
+ color: var(--hi-color-primary, rgb(88 166 255));
68
+ }
69
+
70
+ .hk-morphing-tabs-content {
71
+ flex: 1;
72
+ min-height: 0;
73
+ position: relative;
74
+ display: flex;
75
+ flex-direction: column;
76
+ }
77
+
78
+ .hk-morphing-tabs-panel {
79
+ width: 100%;
80
+ flex: 1;
81
+ min-height: 0;
82
+ display: flex;
83
+ flex-direction: column;
84
+ }
85
+
86
+ .hk-morphing-tabs-footer {
87
+ flex-shrink: 0;
88
+ display: grid;
89
+ grid-template-rows: 1fr;
90
+ transition: grid-template-rows var(--hi-duration-normal, 0.3s) ease;
91
+ overflow: hidden;
92
+ }
93
+
94
+ .hk-morphing-tabs-footer-inner {
95
+ width: 100%;
96
+ min-height: 0;
97
+ }
98
+
99
+ .hk-morphing-crossfade-enter-active {
100
+ transition:
101
+ opacity var(--hi-duration-normal, 0.3s) ease,
102
+ transform var(--hi-duration-normal, 0.3s) cubic-bezier(0.16, 1, 0.3, 1);
103
+ }
104
+
105
+ .hk-morphing-crossfade-leave-active {
106
+ transition:
107
+ opacity var(--hi-duration-fast, 0.15s) ease,
108
+ transform var(--hi-duration-fast, 0.15s) ease-in;
109
+ }
110
+
111
+ .hk-morphing-crossfade-enter-from {
112
+ opacity: 0;
113
+ transform: translateY(-8px);
114
+ }
115
+
116
+ .hk-morphing-crossfade-leave-to {
117
+ opacity: 0;
118
+ transform: translateY(4px);
119
+ }
120
+
121
+ .hk-morphing-bar-enter-active {
122
+ transition:
123
+ opacity var(--hi-duration-normal, 0.3s) ease,
124
+ transform var(--hi-duration-normal, 0.3s) cubic-bezier(0.16, 1, 0.3, 1);
125
+ }
126
+
127
+ .hk-morphing-bar-leave-active {
128
+ transition:
129
+ opacity var(--hi-duration-fast, 0.15s) ease,
130
+ transform var(--hi-duration-fast, 0.15s) ease-in;
131
+ }
132
+
133
+ .hk-morphing-bar-enter-from {
134
+ opacity: 0;
135
+ transform: translateY(8px);
136
+ }
137
+
138
+ .hk-morphing-bar-leave-to {
139
+ opacity: 0;
140
+ transform: translateY(-4px);
141
+ }
@@ -0,0 +1,113 @@
1
+ import { computed, defineComponent, onMounted, ref, Teleport, Transition, type PropType } from "vue";
2
+
3
+ import "./HkMorphingTabs.scss";
4
+
5
+ export interface TabItem {
6
+ key: string;
7
+ label: string;
8
+ disabled?: boolean;
9
+ }
10
+
11
+ export default defineComponent({
12
+ name: "HkMorphingTabs",
13
+ props: {
14
+ modelValue: { type: String, required: true },
15
+ tabs: { type: Array as PropType<TabItem[]>, required: true },
16
+ teleportTo: { type: String, default: undefined },
17
+ tag: { type: String, default: "div" },
18
+ hideTriggers: { type: Boolean, default: false },
19
+ },
20
+ emits: {
21
+ "update:modelValue": (_value: string) => true,
22
+ },
23
+ setup(props, { emit, slots }) {
24
+ const activeKey = computed(() => props.modelValue);
25
+ const ready = ref(false);
26
+
27
+ const tabCount = computed(() => props.tabs.length);
28
+ const tabIndex = computed(() => {
29
+ const idx = props.tabs.findIndex((t) => t.key === activeKey.value);
30
+ return idx >= 0 ? idx : 0;
31
+ });
32
+
33
+ const indicatorStyle = computed(
34
+ () =>
35
+ ({
36
+ "--tab-count": tabCount.value,
37
+ "--tab-index": tabIndex.value,
38
+ }) as Record<string, string | number>,
39
+ );
40
+
41
+ onMounted(() => {
42
+ ready.value = true;
43
+ });
44
+
45
+ function renderTriggers() {
46
+ if (props.hideTriggers) return null;
47
+ return (
48
+ <div class="hk-morphing-tabs-triggers" role="tablist">
49
+ <div class="hk-morphing-tabs-indicator" style={indicatorStyle.value} />
50
+ {props.tabs.map((tab) => {
51
+ const isActive = activeKey.value === tab.key;
52
+ return (
53
+ <button
54
+ key={tab.key}
55
+ role="tab"
56
+ aria-selected={isActive}
57
+ aria-controls={`hk-morphing-tabpanel-${tab.key}`}
58
+ tabindex={isActive ? 0 : -1}
59
+ disabled={tab.disabled}
60
+ class={[
61
+ "hk-morphing-tabs-trigger",
62
+ { "hk-morphing-tabs-trigger-active": isActive },
63
+ ]}
64
+ onClick={() => emit("update:modelValue", tab.key)}
65
+ >
66
+ {tab.label}
67
+ </button>
68
+ );
69
+ })}
70
+ </div>
71
+ );
72
+ }
73
+
74
+ return () => {
75
+ const Tag = props.tag as "div" | "section" | "nav";
76
+ const triggerContent = renderTriggers();
77
+
78
+ return (
79
+ <Tag class="hk-morphing-tabs">
80
+ {props.teleportTo ? (
81
+ ready.value && <Teleport to={props.teleportTo}>{triggerContent}</Teleport>
82
+ ) : (
83
+ <div class="hk-morphing-tabs-header">{triggerContent}</div>
84
+ )}
85
+
86
+ <div class="hk-morphing-tabs-content">
87
+ <Transition name="hk-morphing-crossfade" mode="out-in" appear>
88
+ <div
89
+ key={activeKey.value}
90
+ class="hk-morphing-tabs-panel"
91
+ role="tabpanel"
92
+ id={`hk-morphing-tabpanel-${activeKey.value}`}
93
+ aria-label={props.tabs.find((t) => t.key === activeKey.value)?.label}
94
+ >
95
+ {slots[activeKey.value]?.()}
96
+ </div>
97
+ </Transition>
98
+ </div>
99
+
100
+ {slots.footer && (
101
+ <div class="hk-morphing-tabs-footer">
102
+ <Transition name="hk-morphing-bar" mode="out-in" appear>
103
+ <div key={activeKey.value} class="hk-morphing-tabs-footer-inner">
104
+ {slots.footer({ activeKey: activeKey.value })}
105
+ </div>
106
+ </Transition>
107
+ </div>
108
+ )}
109
+ </Tag>
110
+ );
111
+ };
112
+ },
113
+ });
@@ -0,0 +1,81 @@
1
+ .hk-nav-item {
2
+ display: flex;
3
+ align-items: center;
4
+ gap: 0.5rem;
5
+ padding: 0.5rem 0.75rem;
6
+ border-radius: var(--hi-radius-md, 6px);
7
+ color: var(--hi-color-muted);
8
+ font-size: 0.875rem;
9
+ font-family: inherit;
10
+ line-height: 1.4;
11
+ text-decoration: none;
12
+ background: none;
13
+ border: none;
14
+ width: 100%;
15
+ text-align: left;
16
+ cursor: pointer;
17
+ transition:
18
+ background-color var(--hi-duration-fast, 0.15s) ease,
19
+ color var(--hi-duration-fast, 0.15s) ease;
20
+ user-select: none;
21
+
22
+ &:hover:not([data-disabled]) {
23
+ background: color-mix(in srgb, var(--hi-color-surface) 60%, transparent);
24
+ color: var(--hi-color-text-primary);
25
+ }
26
+
27
+ &[data-active] {
28
+ background: color-mix(in srgb, var(--hi-color-primary) 15%, transparent);
29
+ color: var(--hi-color-primary);
30
+ font-weight: 600;
31
+ }
32
+
33
+ &[data-disabled] {
34
+ opacity: 0.4;
35
+ pointer-events: none;
36
+ }
37
+ }
38
+
39
+ .hk-nav-item-button {
40
+ cursor: pointer;
41
+
42
+ &:focus-visible {
43
+ outline: 2px solid var(--hi-color-primary);
44
+ outline-offset: 2px;
45
+ }
46
+ }
47
+
48
+ .hk-nav-item-link {
49
+ &:focus-visible {
50
+ outline: 2px solid var(--hi-color-primary);
51
+ outline-offset: 2px;
52
+ }
53
+ }
54
+
55
+ .hk-nav-item-icon {
56
+ display: inline-flex;
57
+ align-items: center;
58
+ justify-content: center;
59
+ flex-shrink: 0;
60
+ width: 1rem;
61
+ height: 1rem;
62
+ }
63
+
64
+ .hk-nav-item-label {
65
+ white-space: nowrap;
66
+ overflow: hidden;
67
+ text-overflow: ellipsis;
68
+ }
69
+
70
+ .hk-nav-item-arrow {
71
+ transition: transform 0.2s;
72
+ }
73
+
74
+ .hk-nav-item-arrow-expanded {
75
+ transform: rotate(90deg);
76
+ }
77
+
78
+ .hk-nav-item-children {
79
+ padding-left: 1rem;
80
+ overflow: hidden;
81
+ }
@@ -0,0 +1,157 @@
1
+ import { defineComponent, computed, ref, type PropType } from "vue";
2
+ import type { Component } from "vue";
3
+ import { ChevronRight } from "lucide-vue-next";
4
+ import "./HkNavItem.scss";
5
+
6
+ interface NavItemChild {
7
+ id: string;
8
+ label: string;
9
+ icon?: Component;
10
+ active?: boolean;
11
+ badge?: string;
12
+ }
13
+
14
+ function buildClass(props: { active: boolean; disabled: boolean }, extra: string[] = []) {
15
+ return [
16
+ "hk-nav-item",
17
+ ...extra,
18
+ props.active ? "hk-nav-item-active" : "",
19
+ props.disabled ? "hk-nav-item-disabled" : "",
20
+ ];
21
+ }
22
+
23
+ export default defineComponent({
24
+ name: "HkNavItem",
25
+ props: {
26
+ active: { type: Boolean, default: false },
27
+ disabled: { type: Boolean, default: false },
28
+ to: { type: String, default: undefined },
29
+ href: { type: String, default: undefined },
30
+ children: { type: Array as PropType<NavItemChild[]>, default: undefined },
31
+ },
32
+ emits: {
33
+ click: (_e: MouseEvent) => true,
34
+ },
35
+ setup(props, { slots, emit }) {
36
+ const expanded = ref(false);
37
+
38
+ function toggle() {
39
+ expanded.value = !expanded.value;
40
+ }
41
+
42
+ const content = () => (
43
+ <>
44
+ {slots.icon ? <span class="hk-nav-item-icon">{slots.icon()}</span> : null}
45
+ {slots.default ? <span class="hk-nav-item-label">{slots.default()}</span> : null}
46
+ </>
47
+ );
48
+
49
+ const dataAttrs = computed(() => ({
50
+ "data-active": props.active ? "" : undefined,
51
+ "data-disabled": props.disabled ? "" : undefined,
52
+ }));
53
+
54
+ function onClick(e: MouseEvent) {
55
+ if (props.disabled) {
56
+ e.preventDefault();
57
+ return;
58
+ }
59
+ emit("click", e);
60
+ }
61
+
62
+ const arrow = () => (
63
+ <ChevronRight
64
+ size={16}
65
+ class={["hk-nav-item-arrow", expanded.value ? "hk-nav-item-arrow-expanded" : ""]}
66
+ />
67
+ );
68
+
69
+ const childItems = () => {
70
+ if (!props.children) return null;
71
+ return (
72
+ <div class="hk-nav-item-children">
73
+ {props.children.map((child) => (
74
+ <a
75
+ key={child.id}
76
+ href={`#${child.id}`}
77
+ class={[
78
+ "hk-nav-item",
79
+ "hk-nav-item-link",
80
+ child.active ? "hk-nav-item-active" : "",
81
+ ]}
82
+ data-active={child.active ? "" : undefined}
83
+ >
84
+ {child.icon ? <span class="hk-nav-item-icon">{child.icon}</span> : null}
85
+ <span class="hk-nav-item-label">{child.label}</span>
86
+ {child.badge ? <span class="hk-nav-item-badge">{child.badge}</span> : null}
87
+ </a>
88
+ ))}
89
+ </div>
90
+ );
91
+ };
92
+
93
+ return () => {
94
+ if (props.children) {
95
+ const cls = buildClass(props, ["hk-nav-item-button"]);
96
+ return (
97
+ <div>
98
+ <button
99
+ type="button"
100
+ class={cls}
101
+ {...dataAttrs.value}
102
+ disabled={props.disabled}
103
+ onClick={toggle}
104
+ >
105
+ {content()}
106
+ {arrow()}
107
+ </button>
108
+ {expanded.value ? childItems() : null}
109
+ </div>
110
+ );
111
+ }
112
+
113
+ const cls = buildClass(props, ["hk-nav-item-link"]);
114
+
115
+ if (props.to) {
116
+ return (
117
+ <a
118
+ href={props.to}
119
+ class={cls}
120
+ {...dataAttrs.value}
121
+ aria-disabled={props.disabled}
122
+ aria-current={props.active ? "page" : undefined}
123
+ onClick={onClick}
124
+ >
125
+ {content()}
126
+ </a>
127
+ );
128
+ }
129
+
130
+ if (props.href) {
131
+ return (
132
+ <a
133
+ href={props.href}
134
+ class={cls}
135
+ {...dataAttrs.value}
136
+ aria-disabled={props.disabled}
137
+ onClick={onClick}
138
+ >
139
+ {content()}
140
+ </a>
141
+ );
142
+ }
143
+
144
+ return (
145
+ <button
146
+ type="button"
147
+ class={buildClass(props, ["hk-nav-item-button"])}
148
+ {...dataAttrs.value}
149
+ disabled={props.disabled}
150
+ onClick={(e: MouseEvent) => emit("click", e)}
151
+ >
152
+ {content()}
153
+ </button>
154
+ );
155
+ };
156
+ },
157
+ });
@@ -0,0 +1,154 @@
1
+ .hk-number-input {
2
+ display: block;
3
+ width: 100%;
4
+
5
+ &-disabled {
6
+ opacity: 0.5;
7
+ pointer-events: none;
8
+ }
9
+ }
10
+
11
+ .hk-number-input-inner {
12
+ display: flex;
13
+ align-items: center;
14
+ background: var(--hi-color-surface);
15
+ border: 1px solid var(--hi-color-border);
16
+ border-radius: var(--hi-radius-md, 6px);
17
+ overflow: hidden;
18
+ transition:
19
+ background-color var(--hi-transition-base, 200ms cubic-bezier(0.4, 0, 0.2, 1)),
20
+ border-color var(--hi-transition-base, 200ms cubic-bezier(0.4, 0, 0.2, 1)),
21
+ box-shadow var(--hi-transition-base, 200ms cubic-bezier(0.4, 0, 0.2, 1));
22
+
23
+ &:hover {
24
+ border-color: var(--hi-color-primary);
25
+ }
26
+
27
+ &:focus-within {
28
+ border-color: var(--hi-color-primary);
29
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--hi-color-primary) 12%, transparent);
30
+ }
31
+ }
32
+
33
+ .hk-number-input-field {
34
+ flex: 1;
35
+ min-width: 0;
36
+ background: transparent;
37
+ border: none;
38
+ outline: none;
39
+ color: var(--hi-color-text-primary);
40
+ font-family: inherit;
41
+ font-size: 0.875rem;
42
+ line-height: 1.5;
43
+ padding: 0 0.75rem;
44
+
45
+ &::placeholder {
46
+ color: var(--hi-color-muted);
47
+ opacity: 0.6;
48
+ }
49
+
50
+ -moz-appearance: textfield;
51
+
52
+ &::-webkit-inner-spin-button,
53
+ &::-webkit-outer-spin-button {
54
+ -webkit-appearance: none;
55
+ margin: 0;
56
+ }
57
+ }
58
+
59
+ .hk-number-input-prefix,
60
+ .hk-number-input-suffix {
61
+ display: flex;
62
+ align-items: center;
63
+ flex-shrink: 0;
64
+ color: var(--hi-color-muted);
65
+ font-size: 0.875rem;
66
+ }
67
+
68
+ .hk-number-input-prefix {
69
+ padding-left: 0.75rem;
70
+ }
71
+
72
+ .hk-number-input-suffix {
73
+ padding-right: 0.5rem;
74
+ }
75
+
76
+ .hk-number-input-steppers {
77
+ display: flex;
78
+ flex-direction: column;
79
+ flex-shrink: 0;
80
+ border-left: 1px solid var(--hi-color-border);
81
+ }
82
+
83
+ .hk-number-input-step {
84
+ display: flex;
85
+ align-items: center;
86
+ justify-content: center;
87
+ width: 1.5rem;
88
+ height: 50%;
89
+ padding: 0;
90
+ background: transparent;
91
+ border: none;
92
+ color: var(--hi-color-muted);
93
+ cursor: pointer;
94
+ transition:
95
+ background-color var(--hi-duration-fast, 0.15s) ease,
96
+ color var(--hi-duration-fast, 0.15s) ease;
97
+
98
+ &:hover:not(:disabled) {
99
+ background: color-mix(in srgb, var(--hi-color-surface) 60%, transparent);
100
+ color: var(--hi-color-text-primary);
101
+ }
102
+
103
+ &:active:not(:disabled) {
104
+ background: color-mix(in srgb, var(--hi-color-primary) 15%, transparent);
105
+ color: var(--hi-color-primary);
106
+ }
107
+
108
+ &:disabled {
109
+ opacity: 0.3;
110
+ cursor: not-allowed;
111
+ }
112
+ }
113
+
114
+ /* --- Size variants --- */
115
+
116
+ .hk-number-input-sm .hk-number-input-field {
117
+ font-size: 0.75rem;
118
+ padding: 0 0.5rem;
119
+ height: 1.75rem;
120
+ }
121
+
122
+ .hk-number-input-sm .hk-number-input-step {
123
+ width: 1.25rem;
124
+ }
125
+
126
+ .hk-number-input-sm .hk-number-input-step svg {
127
+ width: 12px;
128
+ height: 12px;
129
+ }
130
+
131
+ .hk-number-input-md .hk-number-input-field {
132
+ font-size: 0.875rem;
133
+ padding: 0 0.75rem;
134
+ height: 2.25rem;
135
+ }
136
+
137
+ .hk-number-input-md .hk-number-input-step {
138
+ width: 1.5rem;
139
+ }
140
+
141
+ .hk-number-input-lg .hk-number-input-field {
142
+ font-size: 1rem;
143
+ padding: 0 1rem;
144
+ height: 2.75rem;
145
+ }
146
+
147
+ .hk-number-input-lg .hk-number-input-step {
148
+ width: 1.75rem;
149
+ }
150
+
151
+ .hk-number-input-lg .hk-number-input-step svg {
152
+ width: 16px;
153
+ height: 16px;
154
+ }