@feugene/granularity 0.18.0 → 0.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.
Files changed (199) hide show
  1. package/dist/chunks/chevron-left-D8AUBAM7.js +23 -0
  2. package/dist/chunks/chevron-left-D8AUBAM7.js.map +1 -0
  3. package/dist/chunks/{chevron-right-BfqMVpbB.js → chevron-right-C6Z01h0X.js} +1 -22
  4. package/dist/chunks/chevron-right-C6Z01h0X.js.map +1 -0
  5. package/dist/chunks/config-8Pcutu1j2.js.map +1 -0
  6. package/dist/chunks/{config-K0C2tcLB.js → config-9PYRZlKE.js} +1 -1
  7. package/dist/chunks/{config-K0C2tcLB.js.map → config-9PYRZlKE.js.map} +1 -1
  8. package/dist/chunks/{config-DEvsMTQE.js → config-BJ7Bv_G2.js} +1 -3
  9. package/dist/chunks/config-BJ7Bv_G2.js.map +1 -0
  10. package/dist/chunks/config-BKvX0q102.js.map +1 -0
  11. package/dist/chunks/{config-gvq_hWNM.js → config-Be9k9bOf.js} +1 -7
  12. package/dist/chunks/config-Be9k9bOf.js.map +1 -0
  13. package/dist/chunks/{config-DpqOnJiz2.js → config-CDat1wXf2.js} +1 -1
  14. package/dist/chunks/config-CDat1wXf2.js.map +1 -0
  15. package/dist/chunks/config-CY0_6cMi2.js.map +1 -0
  16. package/dist/chunks/config-D94Z9po52.js.map +1 -0
  17. package/dist/chunks/{config-D2aNP7Es.js → config-DAX8Deh1.js} +1 -3
  18. package/dist/chunks/config-DAX8Deh1.js.map +1 -0
  19. package/dist/chunks/config-DCFvmHEv.js.map +1 -0
  20. package/dist/chunks/config-DKdlqXiY.js.map +1 -1
  21. package/dist/chunks/config-Rw9OyW702.js.map +1 -0
  22. package/dist/chunks/generated-BRkbhyxk.js +3270 -0
  23. package/dist/chunks/generated-BRkbhyxk.js.map +1 -0
  24. package/dist/chunks/{granular-provider-B9nXQCMu.js → granular-provider-C6uAujdJ.js} +12 -12
  25. package/dist/chunks/{granular-provider-B9nXQCMu.js.map → granular-provider-C6uAujdJ.js.map} +1 -1
  26. package/dist/chunks/grip-vertical-lRha2S7q.js +16 -0
  27. package/dist/chunks/grip-vertical-lRha2S7q.js.map +1 -0
  28. package/dist/chunks/icon-Dag2tIMs.js +21 -0
  29. package/dist/chunks/icon-Dag2tIMs.js.map +1 -0
  30. package/dist/chunks/{portalRoot-CWD4zHBm.js → portalRoot-CVhCgdG6.js} +10 -1
  31. package/dist/chunks/{portalRoot-CWD4zHBm.js.map → portalRoot-CVhCgdG6.js.map} +1 -1
  32. package/dist/chunks/{useModalOverlay-BTq-0ImG.js → useModalOverlay-DrQVYwwA.js} +1 -1
  33. package/dist/chunks/{useModalOverlay-BTq-0ImG.js.map → useModalOverlay-DrQVYwwA.js.map} +1 -1
  34. package/dist/chunks/{usePortalTarget-RyzEgNTb.js → usePortalTarget-Cn-Wiz5d.js} +1 -1
  35. package/dist/chunks/{usePortalTarget-RyzEgNTb.js.map → usePortalTarget-Cn-Wiz5d.js.map} +1 -1
  36. package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-CPEQxmLZ.js → GrAutocomplete-gY4Xopza.js} +32 -24
  37. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-gY4Xopza.js.map +1 -0
  38. package/dist/components/GrAutocomplete/index.js +1 -1
  39. package/dist/components/GrAutocomplete/styles.css +1 -1
  40. package/dist/components/GrBreadcrumbs/chunks/{GrBreadcrumbs-BCNGDS6k.js → GrBreadcrumbs-DS_-PBVt.js} +8 -7
  41. package/dist/components/GrBreadcrumbs/chunks/GrBreadcrumbs-DS_-PBVt.js.map +1 -0
  42. package/dist/components/GrBreadcrumbs/index.js +1 -1
  43. package/dist/components/GrCollapse/chunks/{GrCollapse-B2Fc6A9r.js.map → GrCollapse-Kk0DE8tb.js.map} +1 -1
  44. package/dist/components/GrCollapse/index.js +1 -1
  45. package/dist/components/GrColorPicker/chunks/{GrColorPicker-DAdQ-Gc3.js → GrColorPicker-CkBTzkqn.js} +1 -1
  46. package/dist/components/GrColorPicker/chunks/{GrColorPicker-DAdQ-Gc3.js.map → GrColorPicker-CkBTzkqn.js.map} +1 -1
  47. package/dist/components/GrColorPicker/index.js +1 -1
  48. package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-DMeSqkEv.js → GrCommandPalette-BugTlGdj.js} +37 -11
  49. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-BugTlGdj.js.map +1 -0
  50. package/dist/components/GrCommandPalette/index.js +2 -2
  51. package/dist/components/GrCommandPalette/styles.css +1 -1
  52. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-hUTi-GdJ.js → GrConfirmDialog-Ds5T0GiR.js} +1 -1
  53. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-hUTi-GdJ.js.map → GrConfirmDialog-Ds5T0GiR.js.map} +1 -1
  54. package/dist/components/GrConfirmDialog/index.js +1 -1
  55. package/dist/components/GrDataTable/chunks/{GrDataTable-DzaGLG3A.js → GrDataTable-CYe2A2WA.js} +9 -7
  56. package/dist/components/GrDataTable/chunks/GrDataTable-CYe2A2WA.js.map +1 -0
  57. package/dist/components/GrDataTable/index.js +2 -2
  58. package/dist/components/GrDialog/chunks/{GrDialog-MD9Fzy9C.js → GrDialog-C3tYaA8v.js} +1 -1
  59. package/dist/components/GrDialog/chunks/{GrDialog-MD9Fzy9C.js.map → GrDialog-C3tYaA8v.js.map} +1 -1
  60. package/dist/components/GrDialog/index.js +1 -1
  61. package/dist/components/GrDialogService/chunks/{GrDialogService-DtgUijMj.js → GrDialogService-CTBiiJDI.js} +3 -3
  62. package/dist/components/GrDialogService/chunks/{GrDialogService-DtgUijMj.js.map → GrDialogService-CTBiiJDI.js.map} +1 -1
  63. package/dist/components/GrDialogService/index.js +1 -1
  64. package/dist/components/GrDivider/chunks/{GrDivider-B2Xwc_QO.js → GrDivider-xxq1_fIl.js} +1 -1
  65. package/dist/components/GrDivider/chunks/{GrDivider-B2Xwc_QO.js.map → GrDivider-xxq1_fIl.js.map} +1 -1
  66. package/dist/components/GrDivider/index.js +2 -2
  67. package/dist/components/GrDrawer/chunks/{GrDrawer-DWHdZZzW.js → GrDrawer-BSSuiNHU.js} +2 -2
  68. package/dist/components/GrDrawer/chunks/{GrDrawer-DWHdZZzW.js.map → GrDrawer-BSSuiNHU.js.map} +1 -1
  69. package/dist/components/GrDrawer/index.js +2 -2
  70. package/dist/components/GrDropdown/chunks/{GrDropdown-0tJK01Kq.js → GrDropdown-Bh6UK2M5.js} +1 -1
  71. package/dist/components/GrDropdown/chunks/{GrDropdown-0tJK01Kq.js.map → GrDropdown-Bh6UK2M5.js.map} +1 -1
  72. package/dist/components/GrDropdown/index.js +1 -1
  73. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-VPPrpCoA.js → GrDropdownMenu-LyfEFUbg.js} +2 -2
  74. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-VPPrpCoA.js.map → GrDropdownMenu-LyfEFUbg.js.map} +1 -1
  75. package/dist/components/GrDropdownMenu/index.js +2 -2
  76. package/dist/components/GrImageViewer/chunks/{GrImageViewer-DE7MBbF8.js → GrImageViewer-DfD4euH5.js} +3 -2
  77. package/dist/components/GrImageViewer/chunks/{GrImageViewer-DE7MBbF8.js.map → GrImageViewer-DfD4euH5.js.map} +1 -1
  78. package/dist/components/GrImageViewer/index.js +1 -1
  79. package/dist/components/GrModal/chunks/{GrModal-BbhcsDQ8.js → GrModal-CbMMr6W1.js} +1 -1
  80. package/dist/components/GrModal/chunks/{GrModal-BbhcsDQ8.js.map → GrModal-CbMMr6W1.js.map} +1 -1
  81. package/dist/components/GrModal/index.js +1 -1
  82. package/dist/components/GrNumberInput/chunks/{GrNumberInput-CZOyPz4J.js → GrNumberInput-B5CHZDBj.js} +2 -1
  83. package/dist/components/GrNumberInput/chunks/{GrNumberInput-CZOyPz4J.js.map → GrNumberInput-B5CHZDBj.js.map} +1 -1
  84. package/dist/components/GrNumberInput/index.js +1 -1
  85. package/dist/components/GrPagination/chunks/{GrPagination-waKhxBP7.js → GrPagination-BM4FrD6Q.js} +1 -1
  86. package/dist/components/GrPagination/chunks/{GrPagination-waKhxBP7.js.map → GrPagination-BM4FrD6Q.js.map} +1 -1
  87. package/dist/components/GrPagination/index.js +1 -1
  88. package/dist/components/GrPopover/chunks/{GrPopover-DuqeoFaI.js → GrPopover-DMH4Jjst.js} +1 -1
  89. package/dist/components/GrPopover/chunks/{GrPopover-DuqeoFaI.js.map → GrPopover-DMH4Jjst.js.map} +1 -1
  90. package/dist/components/GrPopover/index.js +1 -1
  91. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-JVVqBsPY.js → GrPromptDialog-Pwr9NPxK.js} +1 -1
  92. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-JVVqBsPY.js.map → GrPromptDialog-Pwr9NPxK.js.map} +1 -1
  93. package/dist/components/GrPromptDialog/index.js +1 -1
  94. package/dist/components/GrRating/chunks/{GrRating-LarIiwJL.js → GrRating-DVFH3lYu.js} +8 -7
  95. package/dist/components/GrRating/chunks/GrRating-DVFH3lYu.js.map +1 -0
  96. package/dist/components/GrRating/index.js +1 -1
  97. package/dist/components/GrSelect/chunks/{GrSelect-DAdu044K.js → GrSelect-B-Voni7D.js} +65 -52
  98. package/dist/components/GrSelect/chunks/GrSelect-B-Voni7D.js.map +1 -0
  99. package/dist/components/GrSelect/index.js +1 -1
  100. package/dist/components/GrSelect/styles.css +1 -1
  101. package/dist/components/GrSidebar/chunks/{GrSidebar-DRGnnViw.js → GrSidebar-i7AxjhY_.js} +3 -2
  102. package/dist/components/GrSidebar/chunks/{GrSidebar-DRGnnViw.js.map → GrSidebar-i7AxjhY_.js.map} +1 -1
  103. package/dist/components/GrSidebar/index.js +2 -2
  104. package/dist/components/GrSkeleton/index.js +1 -1
  105. package/dist/components/GrSortableList/chunks/{GrSortableList-BefVfWKh.js → GrSortableList-XB7mXM1W.js} +6 -5
  106. package/dist/components/GrSortableList/chunks/GrSortableList-XB7mXM1W.js.map +1 -0
  107. package/dist/components/GrSortableList/index.js +2 -2
  108. package/dist/components/GrStatistic/chunks/{GrStatistic-J4qLs3TH.js → GrStatistic-DOsM6s5V.js} +54 -7
  109. package/dist/components/GrStatistic/chunks/GrStatistic-DOsM6s5V.js.map +1 -0
  110. package/dist/components/GrStatistic/index.js +2 -2
  111. package/dist/components/GrTabs/chunks/{GrTabs-TeXaU5Uh.js → GrTabs-f3-oQenu.js} +5 -4
  112. package/dist/components/GrTabs/chunks/GrTabs-f3-oQenu.js.map +1 -0
  113. package/dist/components/GrTabs/index.js +1 -1
  114. package/dist/components/GrToaster/chunks/{GrToaster-Ct-39hga.js → GrToaster-Dqja0Lf9.js} +1 -1
  115. package/dist/components/GrToaster/chunks/{GrToaster-Ct-39hga.js.map → GrToaster-Dqja0Lf9.js.map} +1 -1
  116. package/dist/components/GrToaster/index.js +1 -1
  117. package/dist/components/GrTooltip/chunks/{GrTooltip-xAcqs0bP.js → GrTooltip-Cn08heWz.js} +1 -1
  118. package/dist/components/GrTooltip/chunks/{GrTooltip-xAcqs0bP.js.map → GrTooltip-Cn08heWz.js.map} +1 -1
  119. package/dist/components/GrTooltip/index.js +1 -1
  120. package/dist/components/GrTree/chunks/{GrTree-CaYK8dGZ.js → GrTree-BR9a2pay.js} +25 -20
  121. package/dist/components/GrTree/chunks/GrTree-BR9a2pay.js.map +1 -0
  122. package/dist/components/GrTree/index.js +2 -2
  123. package/dist/components/GrTree/styles.css +1 -1
  124. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DZp7CqqW.js → GrTreeSelect--muUeB0v.js} +27 -13
  125. package/dist/components/GrTreeSelect/chunks/GrTreeSelect--muUeB0v.js.map +1 -0
  126. package/dist/components/GrTreeSelect/index.js +2 -2
  127. package/dist/composables/useAnnouncer.js +1 -1
  128. package/dist/composables/usePortalTarget.js +1 -1
  129. package/dist/directives/loading.js +1 -1
  130. package/dist/granular-provider-node.js +1 -1
  131. package/dist/granular-provider.js +1 -1
  132. package/dist/index.js +41 -41
  133. package/dist/styles/themes/dark.css +6 -1
  134. package/dist/testing.js +199 -0
  135. package/dist/testing.js.map +1 -0
  136. package/dist/theme-apply.js +33 -0
  137. package/dist/theme-apply.js.map +1 -0
  138. package/dist/theme.js +501 -0
  139. package/dist/theme.js.map +1 -0
  140. package/dist/tokens.js +1 -3215
  141. package/dist/types/src/components/GrBreadcrumbs/grBreadcrumbsStyles.d.ts +5 -2
  142. package/dist/types/src/components/GrCommandPalette/GrCommandPalette.vue.d.ts +6 -6
  143. package/dist/types/src/components/GrCommandPalette/filtering.d.ts +6 -2
  144. package/dist/types/src/components/GrDataTable/grDataTableStyles.d.ts +0 -1
  145. package/dist/types/src/components/GrRating/GrRating.vue.d.ts +9 -4
  146. package/dist/types/src/components/GrSortableList/grSortableListStyles.d.ts +0 -1
  147. package/dist/types/src/components/GrStatistic/GrStatistic.vue.d.ts +12 -9
  148. package/dist/types/src/components/GrStatistic/grStatisticStyles.d.ts +0 -1
  149. package/dist/types/src/components/GrTabs/GrTabs.vue.d.ts +6 -2
  150. package/dist/types/src/components/GrTree/grTreeProps.d.ts +11 -4
  151. package/dist/types/src/components/GrTree/safelist.d.ts +1 -1
  152. package/dist/types/src/components/shared/icon.d.ts +13 -0
  153. package/dist/types/src/testing/announcer.d.ts +10 -0
  154. package/dist/types/src/testing/context.d.ts +36 -0
  155. package/dist/types/src/testing/env.d.ts +25 -0
  156. package/dist/types/src/testing/geometry.d.ts +23 -0
  157. package/dist/types/src/testing/index.d.ts +12 -0
  158. package/dist/types/src/testing/pointer.d.ts +31 -0
  159. package/dist/types/src/theme/apply.d.ts +27 -0
  160. package/dist/types/src/theme/color.d.ts +35 -0
  161. package/dist/types/src/theme/extendTheme.d.ts +63 -0
  162. package/dist/types/src/theme/index.d.ts +22 -0
  163. package/dist/types/src/theme/roles.d.ts +16 -0
  164. package/dist/types/src/theme/tone.d.ts +32 -0
  165. package/dist/types/src/theme/validate.d.ts +16 -0
  166. package/dist/types/src/tokens/types.d.ts +8 -0
  167. package/dist/web-types.json +14 -11
  168. package/package.json +17 -2
  169. package/tokens/themes/dark.json +2 -1
  170. package/dist/chunks/chevron-right-BfqMVpbB.js.map +0 -1
  171. package/dist/chunks/config-8Pcutu1j.js.map +0 -1
  172. package/dist/chunks/config-BKvX0q10.js.map +0 -1
  173. package/dist/chunks/config-CY0_6cMi.js.map +0 -1
  174. package/dist/chunks/config-D2aNP7Es.js.map +0 -1
  175. package/dist/chunks/config-D94Z9po5.js.map +0 -1
  176. package/dist/chunks/config-DCFvmHEv2.js.map +0 -1
  177. package/dist/chunks/config-DEvsMTQE.js.map +0 -1
  178. package/dist/chunks/config-DpqOnJiz2.js.map +0 -1
  179. package/dist/chunks/config-Rw9OyW70.js.map +0 -1
  180. package/dist/chunks/config-gvq_hWNM.js.map +0 -1
  181. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-CPEQxmLZ.js.map +0 -1
  182. package/dist/components/GrBreadcrumbs/chunks/GrBreadcrumbs-BCNGDS6k.js.map +0 -1
  183. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-DMeSqkEv.js.map +0 -1
  184. package/dist/components/GrDataTable/chunks/GrDataTable-DzaGLG3A.js.map +0 -1
  185. package/dist/components/GrRating/chunks/GrRating-LarIiwJL.js.map +0 -1
  186. package/dist/components/GrSelect/chunks/GrSelect-DAdu044K.js.map +0 -1
  187. package/dist/components/GrSortableList/chunks/GrSortableList-BefVfWKh.js.map +0 -1
  188. package/dist/components/GrStatistic/chunks/GrStatistic-J4qLs3TH.js.map +0 -1
  189. package/dist/components/GrTabs/chunks/GrTabs-TeXaU5Uh.js.map +0 -1
  190. package/dist/components/GrTree/chunks/GrTree-CaYK8dGZ.js.map +0 -1
  191. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-DZp7CqqW.js.map +0 -1
  192. package/dist/tokens.js.map +0 -1
  193. package/dist/chunks/{config-8Pcutu1j.js → config-8Pcutu1j2.js} +0 -0
  194. package/dist/chunks/{config-BKvX0q10.js → config-BKvX0q102.js} +0 -0
  195. package/dist/chunks/{config-CY0_6cMi.js → config-CY0_6cMi2.js} +0 -0
  196. package/dist/chunks/{config-D94Z9po5.js → config-D94Z9po52.js} +0 -0
  197. package/dist/chunks/{config-DCFvmHEv2.js → config-DCFvmHEv.js} +0 -0
  198. package/dist/chunks/{config-Rw9OyW70.js → config-Rw9OyW702.js} +0 -0
  199. package/dist/components/GrCollapse/chunks/{GrCollapse-B2Fc6A9r.js → GrCollapse-Kk0DE8tb.js} +1 -1
@@ -7,8 +7,11 @@ export type GrBreadcrumbItem = {
7
7
  href?: string;
8
8
  /** Цель роутерной ссылки: уезжает в `GrLink` через `attrs` вместе с `as`. */
9
9
  to?: unknown;
10
- /** Класс иконки перед подписью (`i-lucide-*`) — иконка декоративна. */
11
- icon?: string;
10
+ /**
11
+ * Иконка перед подписью — декоративна. Vue-компонент либо класс иконки вашей
12
+ * UnoCSS-сборки (`i-lucide-*` требует вашего `presetIcons`).
13
+ */
14
+ icon?: string | Component;
12
15
  disabled?: boolean;
13
16
  /** Доступное имя пункта, когда подписи недостаточно («Настройки» → «Настройки проекта»). */
14
17
  ariaLabel?: string;
@@ -64,18 +64,18 @@ import './defaults';
64
64
  declare function open(): void;
65
65
  declare function close(): void;
66
66
  declare function toggle(): void;
67
- declare var __VLS_15: {
67
+ declare var __VLS_25: {
68
68
  item: GrCommandItem;
69
69
  active: boolean;
70
- }, __VLS_22: {
70
+ }, __VLS_37: {
71
71
  query: string;
72
- }, __VLS_24: {};
72
+ }, __VLS_39: {};
73
73
  type __VLS_Slots = {} & {
74
- item?: (props: typeof __VLS_15) => any;
74
+ item?: (props: typeof __VLS_25) => any;
75
75
  } & {
76
- empty?: (props: typeof __VLS_22) => any;
76
+ empty?: (props: typeof __VLS_37) => any;
77
77
  } & {
78
- footer?: (props: typeof __VLS_24) => any;
78
+ footer?: (props: typeof __VLS_39) => any;
79
79
  };
80
80
  declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<GrCommandPaletteProps>, {
81
81
  items: undefined;
@@ -1,11 +1,15 @@
1
+ import type { Component } from 'vue';
1
2
  /** Команда палитры. `id` обязателен — он же ключ рендера и цель `aria-activedescendant`. */
2
3
  export type GrCommandItem = {
3
4
  id: string;
4
5
  label: string;
5
6
  /** Пояснение под меткой. */
6
7
  description?: string;
7
- /** UnoCSS-класс иконки (например `i-lucide-file-plus`). */
8
- icon?: string;
8
+ /**
9
+ * Иконка команды: Vue-компонент либо класс иконки вашей UnoCSS-сборки
10
+ * (`'i-lucide-file-plus'` — тогда нужен ваш `presetIcons`).
11
+ */
12
+ icon?: string | Component;
9
13
  /** Подсказка сочетания клавиш — массив клавиш, каждая рисуется отдельным `GrKbd`. */
10
14
  shortcut?: string[];
11
15
  /** Заголовок группы, под которой команда показывается в списке. */
@@ -18,7 +18,6 @@ export declare const placeholderPaddings: Record<GrDataTableSize, string>;
18
18
  */
19
19
  export declare const columnHandleClass = "inline-flex shrink-0 cursor-grab items-center text-[var(--gr-datatable-drag-handle,var(--gr-muted-fg))] opacity-0 [touch-action:none] transition-opacity duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)] rounded-[var(--gr-radius-sm)] group-hover:opacity-100";
20
20
  export declare const columnHandleActiveClass = "opacity-100";
21
- export declare const columnHandleIconClass = "i-lucide-grip-vertical block";
22
21
  /** Переносимая колонка гасится, чтобы было видно, что она «поднята». */
23
22
  export declare const columnDraggingClass = "bg-[var(--gr-muted)]";
24
23
  /**
@@ -1,3 +1,4 @@
1
+ import { type Component } from 'vue';
1
2
  import { type GrRatingSize, type GrRatingTone } from './grRatingStyles';
2
3
  export type { GrRatingSize, GrRatingTone, } from './grRatingStyles';
3
4
  /**
@@ -10,7 +11,7 @@ export type { GrRatingSize, GrRatingTone, } from './grRatingStyles';
10
11
  *
11
12
  * Символ по умолчанию рисуется инлайновым SVG (звезда с `fill="currentColor"`) —
12
13
  * иконочные шрифты-маски `i-lucide-star` дают только контур. Свой символ
13
- * задаётся пропом `icon` (UnoCSS-класс иконки) или слотом `#symbol`.
14
+ * задаётся пропом `icon` (Vue-компонент или класс иконки) либо слотом `#symbol`.
14
15
  */
15
16
  export interface GrRatingProps {
16
17
  /** Текущая оценка. Дробная (`3.5`) поддерживается при `allowHalf`. */
@@ -31,8 +32,12 @@ export interface GrRatingProps {
31
32
  required?: boolean;
32
33
  /** Повторный клик по текущей оценке сбрасывает её в `0`. */
33
34
  clearable?: boolean;
34
- /** UnoCSS-класс иконки вместо встроенной звезды (например `i-lucide-heart`). */
35
- icon?: string;
35
+ /**
36
+ * Символ вместо встроенной звезды: Vue-компонент либо класс иконки вашей
37
+ * UnoCSS-сборки (`'i-lucide-heart'` — тогда нужен ваш `presetIcons`,
38
+ * см. `docs/installation.md`).
39
+ */
40
+ icon?: string | Component;
36
41
  /** Показывать числовую подпись справа от шкалы. */
37
42
  showText?: boolean;
38
43
  /** Формат подписи. По умолчанию — само значение. Сильнее `texts`. */
@@ -131,7 +136,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
131
136
  tone: GrRatingTone;
132
137
  size: GrRatingSize;
133
138
  clearable: boolean;
134
- icon: string;
139
+ icon: string | Component;
135
140
  readonly: boolean;
136
141
  name: string;
137
142
  invalid: boolean;
@@ -28,7 +28,6 @@ export declare const emptyClass = "px-4 py-6 text-center text-[length:var(--gr-t
28
28
  */
29
29
  export declare const handleClass = "flex shrink-0 items-center justify-center rounded-[var(--gr-radius-sm)] text-[var(--gr-sortable-handle-color,var(--gr-muted-fg))] size-[var(--gr-sortable-handle-size,1.5rem)] cursor-grab [touch-action:none] focus:outline-none";
30
30
  export declare const handleDisabledClass = "cursor-not-allowed text-[var(--gr-muted-fg)]";
31
- export declare const handleIconClass = "i-lucide-grip-vertical";
32
31
  export declare const contentClass = "min-w-0 flex-1 text-[length:var(--gr-text-sm)]";
33
32
  /**
34
33
  * Куда встанет строка — псевдоэлемент самой строки, а не отдельный узел:
@@ -29,8 +29,11 @@ export interface GrStatisticProps {
29
29
  prefix?: string;
30
30
  /** Приписка после значения (единица измерения, `%`). */
31
31
  suffix?: string;
32
- /** UnoCSS-класс иконки слева от блока (например `i-lucide-users`). */
33
- icon?: string;
32
+ /**
33
+ * Иконка слева от блока: Vue-компонент либо класс иконки вашей UnoCSS-сборки
34
+ * (`'i-lucide-users'` — тогда нужен ваш `presetIcons`, см. `docs/installation.md`).
35
+ */
36
+ icon?: string | Component;
34
37
  size?: GrStatisticSize;
35
38
  /** Тон значения; точечно перекрывается `--gr-statistic-value-color`. */
36
39
  tone?: GrStatisticTone;
@@ -61,19 +64,19 @@ export interface GrStatisticProps {
61
64
  export interface GrStatisticEmits {
62
65
  (e: 'click', event: MouseEvent): void;
63
66
  }
64
- declare var __VLS_10: {}, __VLS_18: {}, __VLS_37: {}, __VLS_39: {}, __VLS_41: {}, __VLS_43: {};
67
+ declare var __VLS_10: {}, __VLS_23: {}, __VLS_42: {}, __VLS_44: {}, __VLS_46: {}, __VLS_48: {};
65
68
  type __VLS_Slots = {} & {
66
69
  icon?: (props: typeof __VLS_10) => any;
67
70
  } & {
68
- title?: (props: typeof __VLS_18) => any;
71
+ title?: (props: typeof __VLS_23) => any;
69
72
  } & {
70
- prefix?: (props: typeof __VLS_37) => any;
73
+ prefix?: (props: typeof __VLS_42) => any;
71
74
  } & {
72
- default?: (props: typeof __VLS_39) => any;
75
+ default?: (props: typeof __VLS_44) => any;
73
76
  } & {
74
- suffix?: (props: typeof __VLS_41) => any;
77
+ suffix?: (props: typeof __VLS_46) => any;
75
78
  } & {
76
- trend?: (props: typeof __VLS_43) => any;
79
+ trend?: (props: typeof __VLS_48) => any;
77
80
  };
78
81
  declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<GrStatisticProps>, {
79
82
  title: undefined;
@@ -121,7 +124,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
121
124
  tone: GrStatisticTone;
122
125
  size: GrStatisticSize;
123
126
  title: string;
124
- icon: string;
127
+ icon: string | Component;
125
128
  animate: boolean;
126
129
  href: string;
127
130
  loading: boolean;
@@ -17,7 +17,6 @@ export declare const statisticPlaceholderHeightBySize: Record<GrStatisticSize, s
17
17
  export declare const statisticTrendSizeBySize: Record<GrStatisticSize, string>;
18
18
  export declare const statisticValueClassByTone: Record<GrStatisticTone, string>;
19
19
  export declare const statisticTrendClassByTrend: Record<GrStatisticTrend, string>;
20
- export declare const statisticTrendIconByTrend: Record<GrStatisticTrend, string>;
21
20
  export declare const statisticTitleClass = "font-medium tracking-wide text-[var(--gr-statistic-title-color,var(--gr-muted-fg))]";
22
21
  export declare const statisticRootBase = "flex items-start gap-3 text-left";
23
22
  /**
@@ -1,10 +1,14 @@
1
+ import { type Component } from 'vue';
1
2
  import { type GrTabsOrientation, type GrTabsSize, type GrTabsVariant } from './grTabsStyles';
2
3
  export interface GrTab {
3
4
  value: string;
4
5
  label: string;
5
6
  badge?: string;
6
- /** UnoCSS-класс иконки слева от подписи (например `i-lucide-user`). */
7
- icon?: string;
7
+ /**
8
+ * Иконка слева от подписи: Vue-компонент либо класс иконки вашей UnoCSS-сборки
9
+ * (`'i-lucide-user'` — тогда нужен ваш `presetIcons`, см. `docs/installation.md`).
10
+ */
11
+ icon?: string | Component;
8
12
  disabled?: boolean;
9
13
  /** Перекрывает `closable` ряда в обе стороны: закрепить вкладку или закрыть одну её. */
10
14
  closable?: boolean;
@@ -1,4 +1,4 @@
1
- import type { HTMLAttributes } from 'vue';
1
+ import type { Component, HTMLAttributes } from 'vue';
2
2
  import type { GrTreeSize } from './grTreeStyles';
3
3
  import type { GrTreeAllowDropType, GrTreeKey, GrTreeNode } from './grTreeTypes';
4
4
  export type NodeKeyProp<T extends object> = Extract<keyof T, string>;
@@ -71,8 +71,14 @@ export type GrTreeViewProps<T extends object> = {
71
71
  /** Максимальная высота дерева со своим скроллером. Число — пиксели. */
72
72
  maxHeight?: number | string;
73
73
  highlightCurrent?: boolean;
74
- expandIcon?: string;
75
- collapseIcon?: string;
74
+ /**
75
+ * Иконка свёрнутого узла: Vue-компонент либо класс иконки вашей UnoCSS-сборки
76
+ * (`'i-lucide-plus'` — тогда нужен ваш `presetIcons`, см. `docs/installation.md`).
77
+ * Не задана — встроенная стрелка.
78
+ */
79
+ expandIcon?: string | Component;
80
+ /** Иконка раскрытого узла. Не задана — та же встроенная стрелка, повёрнутая. */
81
+ collapseIcon?: string | Component;
76
82
  toggleIconRotate?: boolean;
77
83
  branchLine?: boolean;
78
84
  branchLineColor?: GrTreeBranchLineColor<T>;
@@ -96,7 +102,8 @@ export type GrTreeInteractionProps<T extends object> = {
96
102
  /** На каждом уровне раскрыт максимум один узел. */
97
103
  accordion?: boolean;
98
104
  draggable?: boolean;
99
- dragHandleIcon?: string;
105
+ /** Иконка ручки переноса: компонент, класс иконки или ничего — тогда встроенная. */
106
+ dragHandleIcon?: string | Component;
100
107
  allowDrop?: (draggingNode: GrTreeNode<T>, dropNode: GrTreeNode<T>, type: GrTreeAllowDropType) => boolean;
101
108
  allowDrag?: (draggingNode: GrTreeNode<T>) => boolean;
102
109
  };
@@ -1 +1 @@
1
- export declare const grTreeSafelist: readonly ["i-lucide-chevron-right", "i-lucide-grip-vertical"];
1
+ export declare const grTreeSafelist: readonly [];
@@ -0,0 +1,13 @@
1
+ import type { Component } from 'vue';
2
+ /**
3
+ * Иконку компонент получает двумя способами, и рисуются они разными тегами.
4
+ *
5
+ * Vue-компонент пакет рисует сам — он ни от чего не зависит. Класс иконки
6
+ * (`i-lucide-*`) генерирует не пакет, а UnoCSS-сборка приложения: без своего
7
+ * `presetIcons` потребитель получит пустое место вместо картинки
8
+ * (`docs/installation.md`). Поэтому класс уезжает в `:class` пустого `span`,
9
+ * а компонент — в `:is`.
10
+ */
11
+ export declare function iconTag(icon: string | Component | undefined, fallback?: string | Component): string | Component;
12
+ /** Класс иконки, если она задана строкой; для компонента классов нет. */
13
+ export declare function iconClass(icon: string | Component | undefined): string;
@@ -0,0 +1,10 @@
1
+ import type { GrAnnouncerPoliteness } from '../composables/useAnnouncer';
2
+ /**
3
+ * Текст живого региона.
4
+ *
5
+ * Ждать здесь обязательно: `announce` пишет в регион **отложенным** макротаском,
6
+ * и это не деталь реализации, а условие работы. Регион, в котором текст
7
+ * появился в том же кадре, что и сам регион, часть AT не объявляет вовсе;
8
+ * поэтому синхронное чтение сразу после действия покажет пустую строку.
9
+ */
10
+ export declare function announced(politeness?: GrAnnouncerPoliteness): Promise<string>;
@@ -0,0 +1,36 @@
1
+ import { type Ref } from 'vue';
2
+ import { type GrComponentDefaults, type GrComponentSize } from '../components/GrConfigProvider/context';
3
+ import { type GranularityI18nAdapter, type GranularityI18nParams } from '../i18n/adapter';
4
+ export interface I18nAdapterOptions {
5
+ /** Перевод по ключу. По умолчанию — сам ключ: видно, что спросили. */
6
+ t?: (key: string, params?: GranularityI18nParams) => string;
7
+ te?: (key: string) => boolean;
8
+ locale?: string | Ref<string>;
9
+ }
10
+ /** Адаптер перевода для теста: словарь или своя функция. */
11
+ export declare function i18nAdapter(options?: I18nAdapterOptions | Record<string, string>): GranularityI18nAdapter;
12
+ export interface GranularityGlobalOptions {
13
+ size?: GrComponentSize;
14
+ componentDefaults?: GrComponentDefaults;
15
+ theme?: string;
16
+ portalTarget?: string | HTMLElement;
17
+ /** Адаптер перевода: готовый, словарь `{ ключ: перевод }` или опции `i18nAdapter`. */
18
+ i18n?: GranularityI18nAdapter | I18nAdapterOptions | Record<string, string>;
19
+ }
20
+ /**
21
+ * Окружение пакета для монтирования — то, что `<GrConfigProvider>` раздаёт
22
+ * через `provide`.
23
+ *
24
+ * Отдаётся объектом, а не компонентом-обёрткой, намеренно: провайдер тянет за
25
+ * собой лишний корневой элемент, а искать компонент внутри чужой разметки в
26
+ * каждом тесте дороже, чем передать `global`. Проверять **сам** провайдер
27
+ * (`data-gr-config-provider`, тема на корне) этим нельзя и не нужно — для этого
28
+ * его и монтируют.
29
+ *
30
+ * ```ts
31
+ * mount(GrSelect, { props, global: granularityGlobal({ size: 'sm' }) })
32
+ * ```
33
+ */
34
+ export declare function granularityGlobal(options?: GranularityGlobalOptions): {
35
+ provide: Record<symbol, unknown>;
36
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Уборка между тестами.
3
+ *
4
+ * `document.body.innerHTML = ''` сам по себе оставляет пакет в разобранном
5
+ * состоянии: корень портала и хост живого региона закэшированы модулями, и
6
+ * после очистки `body` они указывают на узлы **вне документа**. Следующий
7
+ * монтаж телепортирует туда оверлеи, тест ищет их в документе и не находит —
8
+ * без единой ошибки в консоли. Очередь тостов переживает размонтирование по
9
+ * замыслу, поэтому её тоже гасим.
10
+ */
11
+ export declare function resetGranularityDom(): void;
12
+ export interface StubMatchMediaOptions {
13
+ /** Ответ на `(prefers-reduced-motion: reduce)`. */
14
+ reducedMotion?: boolean;
15
+ /** Ответ на остальные запросы. */
16
+ matches?: boolean;
17
+ }
18
+ /**
19
+ * Ответ `matchMedia` — например «пользователь просил меньше движения».
20
+ *
21
+ * Не для того, чтобы «не падало»: сам пакет зовёт `matchMedia` опционально и без
22
+ * него живёт. Нужно, когда проверяется поведение **под** медиазапросом.
23
+ * Возвращает функцию отката: глобальное состояние обязано уйти вместе с тестом.
24
+ */
25
+ export declare function stubMatchMedia(options?: StubMatchMediaOptions): () => void;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Геометрия в jsdom.
3
+ *
4
+ * Раскладки в jsdom нет: `getBoundingClientRect` у любого элемента возвращает
5
+ * нули. Всё, что считает попадание указателя — слайдер, сплиттер, перестановка,
6
+ * ширины колонок таблицы, — на нулевом прямоугольнике проверять не на чем,
7
+ * поэтому геометрия задаётся руками.
8
+ */
9
+ export type MockRect = Partial<Omit<DOMRect, 'toJSON'>>;
10
+ /** Прямоугольник элемента. Незаданные стороны выводятся из заданных. */
11
+ export declare function mockRect(target: Element, rect: MockRect): void;
12
+ export interface StackRectsOptions {
13
+ /** Размер элемента вдоль оси. */
14
+ size: number;
15
+ /** Ось раскладки. По умолчанию вертикальная — так лежат списки и строки. */
16
+ axis?: 'vertical' | 'horizontal';
17
+ /** Смещение первого элемента. */
18
+ start?: number;
19
+ /** Размер поперёк оси. */
20
+ cross?: number;
21
+ }
22
+ /** Элементы подряд, встык, без зазоров: строки списка, ячейки шапки, деления шкалы. */
23
+ export declare function stackRects(targets: Iterable<Element>, options: StackRectsOptions): void;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Тестовые утилиты пакета — `@feugene/granularity/testing`.
3
+ *
4
+ * Ни `vitest`, ни `@vue/test-utils` здесь нет и не будет: утилиты отдают данные
5
+ * и действия над DOM, а монтирует и утверждает потребитель — своим раннером.
6
+ * Документация: `docs/testing.md`.
7
+ */
8
+ export { cancelPointer, drag, move, pointer, press, release } from './pointer';
9
+ export { mockRect, type MockRect, stackRects, type StackRectsOptions } from './geometry';
10
+ export { resetGranularityDom, stubMatchMedia, type StubMatchMediaOptions } from './env';
11
+ export { granularityGlobal, type GranularityGlobalOptions, i18nAdapter, type I18nAdapterOptions } from './context';
12
+ export { announced } from './announcer';
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Указательные жесты в тестах.
3
+ *
4
+ * Две вещи, которые ломают наивную запись жеста, и обе неочевидны:
5
+ *
6
+ * 1. **`pointerdown` идёт в элемент, а `pointermove`/`pointerup`/`pointercancel` — в `window`.**
7
+ * Так слушает `useDragGesture` (и всё, что на нём стоит: слайдер, сплиттер,
8
+ * перестановка, смахивание тоста): нажатие приходит от разметки, а движение
9
+ * ловится глобально, иначе жест обрывался бы на выходе курсора за элемент.
10
+ * Тест, отправивший движение в тот же элемент, ничего не проверяет — и молча.
11
+ * 2. **`PointerEvent` в jsdom нет**, а `wrapper.trigger('pointerdown', { clientY })`
12
+ * падает на попытке записать `clientY`. Поэтому события собираются
13
+ * `MouseEvent`-ом и отправляются через `dispatchEvent`.
14
+ *
15
+ * Плюс `button: 0` по умолчанию: жест игнорирует неосновную кнопку, и без этого
16
+ * «перетаскивание» в тесте не начинается вовсе.
17
+ */
18
+ /** Событие указателя: `MouseEvent`, потому что `PointerEvent` в jsdom не реализован. */
19
+ export declare function pointer(type: string, init?: MouseEventInit): MouseEvent;
20
+ /** Нажатие: единственное событие жеста, которое адресуется элементу. */
21
+ export declare function press(target: Element, init?: MouseEventInit): void;
22
+ export declare function move(init?: MouseEventInit): void;
23
+ export declare function release(init?: MouseEventInit): void;
24
+ /**
25
+ * Обрыв жеста: система забрала указатель (системный жест, звонок, потеря окна).
26
+ * Отдельная ветка поведения у всех потребителей — смахивание возвращает тост,
27
+ * перестановка откатывает порядок, — поэтому проверяется отдельно от `release`.
28
+ */
29
+ export declare function cancelPointer(init?: MouseEventInit): void;
30
+ /** Жест целиком: нажали на элементе, провели, отпустили. */
31
+ export declare function drag(target: Element, from: MouseEventInit, to: MouseEventInit): void;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Подключение темы в рантайме — `@feugene/granularity/theme/apply`.
3
+ *
4
+ * Отдельный подпуть от `@feugene/granularity/theme` не по вкусу, а по весу:
5
+ * там справочник токенов (сотня килобайт данных), нужный, чтобы тему
6
+ * **собрать**. Чтобы её **подключить**, не нужно ничего, кроме готовой строки,
7
+ * — и приложению незачем платить за первое, если оно делает второе.
8
+ *
9
+ * Штатный путь всё же другой: собрать тему на сборке и отдать браузеру обычный
10
+ * CSS-файл. Этот модуль — для случаев, когда тема появляется только в браузере:
11
+ * редактор тем, превью, тема из пользовательских настроек.
12
+ */
13
+ export interface ApplyThemeOptions {
14
+ /**
15
+ * Имя, под которым тема живёт в документе. Повторный вызов с тем же именем
16
+ * заменяет её содержимое, а не добавляет второй `<style>`: иначе редактор
17
+ * темы за минуту работы оставил бы в `<head>` сотню слоёв, и побеждал бы
18
+ * последний — то есть результат зависел бы от истории правок.
19
+ */
20
+ name?: string;
21
+ /** Куда вставлять. По умолчанию `document.head`. */
22
+ target?: HTMLElement | null;
23
+ }
24
+ /** Подключает CSS темы и возвращает функцию, которая его снимает. */
25
+ export declare function applyTheme(css: string, options?: ApplyThemeOptions): () => void;
26
+ /** Снимает тему, подключённую `applyTheme`. */
27
+ export declare function removeTheme(name?: string, target?: HTMLElement | null): void;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Цветовая математика пакета — один источник на всех.
3
+ *
4
+ * Одну и ту же формулу считают три разных потребителя: генератор токенов
5
+ * (фолбэки `@supports not (color-mix)`), композиция тем (`extendTheme`, `tone`)
6
+ * и гейты контраста. Расхождение здесь не абстрактно: фолбэки уже жили
7
+ * отдельной копией из сорока хексов, которые обязаны были совпадать с живым
8
+ * `color-mix` до байта, и не совпадали.
9
+ *
10
+ * Модуль читает и генератор (`scripts/generate-tokens.mjs`, запускается
11
+ * `node --experimental-strip-types`), поэтому синтаксис здесь только стираемый:
12
+ * ни `enum`, ни `namespace`, ни параметров-свойств в конструкторах.
13
+ */
14
+ export type Rgb = [number, number, number];
15
+ export declare function parseHex(value: string): Rgb;
16
+ export declare function toHex(channels: Rgb): string;
17
+ /**
18
+ * `color-mix(in srgb, base <amount>%, other)` для непрозрачных цветов — это
19
+ * линейная интерполяция в gamma-кодированном sRGB, то есть ровно то, что делает
20
+ * браузер. Поэтому посчитанный здесь фолбэк совпадает с живым `color-mix`.
21
+ */
22
+ export declare function mixSrgb(baseHex: string, otherHex: string, amount: number): string;
23
+ export declare function luminance(color: string | Rgb): number;
24
+ /** Отношение контраста по WCAG 2.1: от 1 (одинаковые) до 21 (чёрное на белом). */
25
+ export declare function contrast(foreground: string | Rgb, background: string | Rgb): number;
26
+ /**
27
+ * Воспринимаемое расстояние между цветами (ΔE, CIE76).
28
+ *
29
+ * Контраст отвечает на вопрос «читается ли текст», а этот — на вопрос
30
+ * «различит ли человек два тона рядом». Порог заметности около 2.3; всё, что
31
+ * ниже, для глаза один цвет, каким бы разным ни выглядел hex.
32
+ */
33
+ export declare function deltaE(first: string | Rgb, second: string | Rgb): number;
34
+ /** Цвет — это hex, а не `var()`/`rgb()`: производные и контраст считаются только по нему. */
35
+ export declare function isHex(value: string): boolean;
@@ -0,0 +1,63 @@
1
+ import type { GrThemeName } from '../tokens/types';
2
+ import { type GrThemeTokens } from './roles';
3
+ import { type GrThemeIssue } from './validate';
4
+ export interface GrTheme {
5
+ name: string;
6
+ /** Селектор, под которым тема объявлена: по умолчанию `[data-theme='<name>']`. */
7
+ selector: string;
8
+ /** Полный набор ролей: своё поверх базы. */
9
+ tokens: GrThemeTokens;
10
+ /** Покомпонентные токены темы, если заданы. */
11
+ componentTokens: GrThemeTokens;
12
+ /** Готовый CSS, включая фолбэк производных для браузеров без `color-mix`. */
13
+ css: string;
14
+ }
15
+ export interface ExtendThemeOptions {
16
+ name: string;
17
+ /** Готовая тема пакета, чужая тема или просто набор ролей. */
18
+ base: GrThemeName | GrTheme | GrThemeTokens;
19
+ selector?: string;
20
+ /** Что меняем. Всё, чего здесь нет, приходит из базы. */
21
+ tokens?: GrThemeTokens;
22
+ /**
23
+ * Покомпонентные токены (`--gr-button-primary-bg`) — у них своя природа:
24
+ * пакет держит для них отдельный слой и **не** наследует их между темами.
25
+ * Поэтому они не достраиваются из базы, а просто едут в тот же селектор:
26
+ * заданы — переопределены, не заданы — работает дефолт компонента.
27
+ */
28
+ componentTokens?: GrThemeTokens;
29
+ /**
30
+ * Проверка контраста и различимости тонов перед выдачей. Включена: тема,
31
+ * которая не читается, — это дефект, и узнать о нём на сборке дешевле, чем от
32
+ * пользователя. Выключать осознанно, для заведомо декоративных тем.
33
+ */
34
+ validate?: boolean;
35
+ }
36
+ export declare class GrThemeError extends Error {
37
+ issues: GrThemeIssue[];
38
+ constructor(name: string, issues: GrThemeIssue[]);
39
+ }
40
+ export declare function renderThemeCss(theme: Pick<GrTheme, 'name' | 'selector' | 'tokens'> & Partial<Pick<GrTheme, 'componentTokens'>>): string;
41
+ /**
42
+ * Тема поверх готовой: объявляем только то, что меняем.
43
+ *
44
+ * Роль, которую тема не объявила, наследуется не от «своей» базы, а из `:root`,
45
+ * то есть из светлой темы: тёмная тема с забытой ролью получает светлое пятно.
46
+ * Поэтому здесь тема достраивается до полного набора **всех** ролей пакета — и
47
+ * роль, добавленная пакетом завтра, приедет в неё сама, без правок потребителя.
48
+ */
49
+ export declare function extendTheme(options: ExtendThemeOptions): GrTheme;
50
+ /**
51
+ * Тема с нуля: без базы, все роли свои.
52
+ *
53
+ * «Без базы» — это не «ни от чего не наследуется»: в CSS так нельзя. Роль,
54
+ * которую тема не объявила, придёт из `:root`, а `:root` — это **светлая тема
55
+ * пакета**. Независимой тема становится ровно тогда, когда объявляет все роли
56
+ * сама, и здесь это проверяется: не хватает — сборка падает со списком, а не
57
+ * молча подмешивает чужую палитру.
58
+ *
59
+ * Цена честная и её видно: `extendTheme` получает новую роль пакета
60
+ * автоматически, а тема с нуля — упадёт на следующей сборке и потребует решения.
61
+ * Это и есть смысл выбора: полный контроль в обмен на сопровождение.
62
+ */
63
+ export declare function createTheme(options: Omit<ExtendThemeOptions, 'base'>): GrTheme;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Композиция тем — `@feugene/granularity/theme`.
3
+ *
4
+ * Тема объявляет только то, что меняет: остальное приезжает из базы, а не из
5
+ * `:root` (то есть не из светлой темы, как было бы у CSS-файла с пропущенной
6
+ * ролью). Роль, добавленная пакетом завтра, попадёт в собранную тему сама.
7
+ *
8
+ * Точка входа сборочная: она тянет справочник токенов, и место ей в скрипте
9
+ * или конфиге, а не в бандле приложения. Подключение готового CSS в браузере —
10
+ * `@feugene/granularity/theme/apply`.
11
+ *
12
+ * Документация: `docs/theming.md`.
13
+ */
14
+ export { createTheme, extendTheme, GrThemeError, renderThemeCss } from './extendTheme';
15
+ export type { ExtendThemeOptions, GrTheme } from './extendTheme';
16
+ export { GrToneError, tone } from './tone';
17
+ export type { ToneOptions, ToneRole } from './tone';
18
+ export { validateTheme } from './validate';
19
+ export type { GrThemeIssue } from './validate';
20
+ export { resolveRole, themeRoleNames } from './roles';
21
+ export type { GrThemeTokens } from './roles';
22
+ export { contrast, deltaE, mixSrgb } from './color';
@@ -0,0 +1,16 @@
1
+ /** Значения ролей темы: `--gr-bg` → `#041e2b`. */
2
+ export type GrThemeTokens = Record<string, string>;
3
+ /** Роли, известные пакету, в порядке объявления. */
4
+ export declare function themeRoleNames(): string[];
5
+ /**
6
+ * Значение роли, годное для арифметики.
7
+ *
8
+ * Роль вправе ссылаться на другую (`--gr-invalid-brd: var(--gr-danger)`) — такую
9
+ * ссылку разворачиваем, иначе фолбэк и проверки считать не из чего. Всё, что не
10
+ * разворачивается в hex (`rgb(… / .45)` у подложки, `var()` за пределы темы),
11
+ * возвращается как `null`: посчитать нельзя, и выдумывать не надо.
12
+ *
13
+ * Цикл рвём с ошибкой: тема потребителя вправе ошибиться, и упасть надо с
14
+ * именами ролей, а не переполнением стека.
15
+ */
16
+ export declare function resolveRole(tokens: GrThemeTokens, name: string, seen?: string[]): string | null;
@@ -0,0 +1,32 @@
1
+ import type { GrThemeName } from '../tokens/types';
2
+ import { type GrThemeTokens } from './roles';
3
+ export type ToneRole = 'fill' | 'solid' | 'light' | 'text';
4
+ export interface ToneOptions {
5
+ /** Тема, в которой тон будет жить: от неё зависят фон, текст и направление сдвигов. */
6
+ base: GrThemeName | {
7
+ tokens: GrThemeTokens;
8
+ } | GrThemeTokens;
9
+ /**
10
+ * Что выводить. По умолчанию — ровно те роли, которые у этого тона есть **в
11
+ * реестре пакета**: у `--gr-accent` это только `-fg`, у `--gr-primary` нет
12
+ * `-light`. Для имени, которого в реестре нет, выводится полная семья.
13
+ */
14
+ roles?: ToneRole[];
15
+ }
16
+ export declare class GrToneError extends Error {
17
+ constructor(role: string, actual: number, expected: number);
18
+ }
19
+ /**
20
+ * Семья ролей тона из одного цвета.
21
+ *
22
+ * Без неё композиция снимает только объём работы: перекрасив `--gr-success`, вы
23
+ * оставляете `-light`, `-text` и `-solid*` от базовой темы, и они расходятся с
24
+ * новым тоном по контрасту — ловушка №3 из `docs/theming.md`. Правила вывода
25
+ * взяты оттуда же (§«Суффиксы ролей»), пороги проверяются на каждом шаге:
26
+ * не вышло — падаем с именем роли, а не отдаём нечитаемое.
27
+ *
28
+ * ```ts
29
+ * extendTheme({ name: 'ocean', base: 'dark', tokens: { ...tone('success', '#3ddc97', { base: 'dark' }) } })
30
+ * ```
31
+ */
32
+ export declare function tone(name: string, seed: string, options: ToneOptions): GrThemeTokens;
@@ -0,0 +1,16 @@
1
+ import type { GrTheme } from './extendTheme';
2
+ import { type GrThemeTokens } from './roles';
3
+ export interface GrThemeIssue {
4
+ kind: 'contrast' | 'distance';
5
+ /** Роль, из-за которой всё встало. */
6
+ token: string;
7
+ /** На чём проверяли: поверхность либо второй тон. */
8
+ against: string;
9
+ actual: number;
10
+ expected: number;
11
+ message: string;
12
+ }
13
+ export declare function validateTheme(theme: GrTheme | {
14
+ name: string;
15
+ tokens: GrThemeTokens;
16
+ }): GrThemeIssue[];
@@ -50,5 +50,13 @@ export interface GrDerivedToken {
50
50
  section: string;
51
51
  description: string;
52
52
  formula: string;
53
+ /**
54
+ * Слагаемые формулы отдельно от её текста: по ним пересчитывается фолбэк
55
+ * `@supports not (color-mix)` для темы, которой на момент сборки пакета не
56
+ * существовало (`extendTheme`).
57
+ */
58
+ base: string;
59
+ amount: number;
60
+ mixWith: string;
53
61
  values: GrTokenValues;
54
62
  }