@birdycom/omniaui 0.0.0-stage → 0.11.1

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 (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -3
  3. package/bin/lib/add.mjs +126 -0
  4. package/bin/lib/catalog.mjs +169 -0
  5. package/bin/lib/project.mjs +90 -0
  6. package/bin/omniaui.mjs +70 -0
  7. package/dist/code-block.css +163 -0
  8. package/dist/components-extra.css +916 -0
  9. package/dist/components.css +10171 -0
  10. package/dist/components.min.css +1 -0
  11. package/dist/data-table.d.ts +9 -0
  12. package/dist/data-table.js +505 -0
  13. package/dist/docs-ui.css +267 -0
  14. package/dist/oc-theme.css +69 -0
  15. package/dist/parts/.gitkeep +0 -0
  16. package/dist/parts/app-accordion-accent.css +60 -0
  17. package/dist/parts/app-alpha-tabs.css +68 -0
  18. package/dist/parts/app-busy-overlay.css +25 -0
  19. package/dist/parts/app-column-menu.css +85 -0
  20. package/dist/parts/app-confirm-dialog.css +70 -0
  21. package/dist/parts/app-cookie-consent.css +63 -0
  22. package/dist/parts/app-data-table.css +174 -0
  23. package/dist/parts/app-greeting.css +47 -0
  24. package/dist/parts/app-list-toolbar.css +81 -0
  25. package/dist/parts/app-page-header.css +54 -0
  26. package/dist/parts/app-severity-card.css +91 -0
  27. package/dist/parts/app-sidebar-dark.css +15 -0
  28. package/dist/parts/app-sortable-row.css +52 -0
  29. package/dist/parts/app-stat-card.css +68 -0
  30. package/dist/parts/app-table-actions.css +71 -0
  31. package/dist/parts/app-table-compact.css +54 -0
  32. package/dist/parts/app-top-progress.css +68 -0
  33. package/dist/parts/app-tree.css +104 -0
  34. package/dist/parts/app-upgrade-banner.css +90 -0
  35. package/dist/parts/app-version-banner.css +80 -0
  36. package/dist/parts/data-chart-line.css +167 -0
  37. package/dist/parts/forms-affix-input.css +75 -0
  38. package/dist/parts/forms-barcode-input.css +75 -0
  39. package/dist/parts/forms-chip-filter.css +91 -0
  40. package/dist/parts/forms-color-select.css +97 -0
  41. package/dist/parts/forms-decimal-input.css +51 -0
  42. package/dist/parts/forms-filter-counts.css +94 -0
  43. package/dist/parts/forms-language-select.css +89 -0
  44. package/dist/parts/forms-number-input.css +98 -0
  45. package/dist/parts/forms-password-requirements.css +55 -0
  46. package/dist/parts/forms-phone-input.css +85 -0
  47. package/dist/parts/forms-time-input.css +74 -0
  48. package/dist/parts/forms-toggle-field.css +69 -0
  49. package/dist/parts/media-art.css +21 -0
  50. package/dist/parts/media-attachment.css +160 -0
  51. package/dist/parts/media-browser-frame.css +73 -0
  52. package/dist/parts/media-card.css +83 -0
  53. package/dist/parts/media-chat-composer.css +90 -0
  54. package/dist/parts/media-doc-viewer.css +151 -0
  55. package/dist/parts/media-emoji-picker.css +88 -0
  56. package/dist/parts/media-entity-card.css +52 -0
  57. package/dist/parts/media-flip-card.css +78 -0
  58. package/dist/parts/media-image-zoom.css +68 -0
  59. package/dist/parts/media-lightbox.css +131 -0
  60. package/dist/parts/media-message-thread.css +136 -0
  61. package/dist/parts/media-message.css +160 -0
  62. package/dist/parts/media-row.css +78 -0
  63. package/dist/parts/media-stack-card.css +82 -0
  64. package/dist/parts/media-terminal-log.css +76 -0
  65. package/dist/parts/media-thumb.css +71 -0
  66. package/dist/parts/site-fact-list.css +25 -0
  67. package/dist/parts/site-link-arrow.css +34 -0
  68. package/dist/parts/site-marquee.css +34 -0
  69. package/dist/parts/site-next-teaser.css +75 -0
  70. package/dist/parts/site-price-card.css +91 -0
  71. package/dist/parts/site-product-mark.css +66 -0
  72. package/dist/parts/site-project-card.css +111 -0
  73. package/dist/parts/site-prose.css +124 -0
  74. package/dist/parts/site-stack-list.css +48 -0
  75. package/dist/parts/site-timeline.css +54 -0
  76. package/dist/showcase.css +404 -0
  77. package/manifest.json +1108 -0
  78. package/package.json +69 -6
  79. package/snippets/accordion-accent.html +24 -0
  80. package/snippets/accordion.html +11 -0
  81. package/snippets/affix-input.html +30 -0
  82. package/snippets/alert-dialog.html +22 -0
  83. package/snippets/alert.html +5 -0
  84. package/snippets/alpha-tabs.html +37 -0
  85. package/snippets/aspect-ratio.html +15 -0
  86. package/snippets/attachment.html +43 -0
  87. package/snippets/avatar.html +6 -0
  88. package/snippets/back-link.html +5 -0
  89. package/snippets/badge.html +5 -0
  90. package/snippets/barcode-input.html +18 -0
  91. package/snippets/breadcrumb.html +6 -0
  92. package/snippets/browser-frame.html +18 -0
  93. package/snippets/busy-overlay.html +31 -0
  94. package/snippets/button-group.html +21 -0
  95. package/snippets/button.html +8 -0
  96. package/snippets/calendar.html +43 -0
  97. package/snippets/card.html +17 -0
  98. package/snippets/carousel.html +21 -0
  99. package/snippets/chart-line.html +46 -0
  100. package/snippets/chart.html +27 -0
  101. package/snippets/chat-composer.html +21 -0
  102. package/snippets/checkbox.html +5 -0
  103. package/snippets/checklist.html +23 -0
  104. package/snippets/chip-filter.html +14 -0
  105. package/snippets/code-window.html +20 -0
  106. package/snippets/collapsible.html +19 -0
  107. package/snippets/color-field.html +13 -0
  108. package/snippets/color-select.html +18 -0
  109. package/snippets/column-menu.html +38 -0
  110. package/snippets/combobox.html +19 -0
  111. package/snippets/command.html +24 -0
  112. package/snippets/confirm-dialog.html +32 -0
  113. package/snippets/context-menu.html +25 -0
  114. package/snippets/cookie-consent.html +70 -0
  115. package/snippets/copy-field.html +19 -0
  116. package/snippets/counter.html +2 -0
  117. package/snippets/data-table.html +151 -0
  118. package/snippets/date-picker.html +32 -0
  119. package/snippets/decimal-input.html +20 -0
  120. package/snippets/definition-list.html +20 -0
  121. package/snippets/demo-panel.html +18 -0
  122. package/snippets/doc-viewer.html +58 -0
  123. package/snippets/drawer.html +30 -0
  124. package/snippets/dropdown-menu.html +27 -0
  125. package/snippets/dropdown.html +9 -0
  126. package/snippets/dropzone.html +13 -0
  127. package/snippets/emoji-picker.html +51 -0
  128. package/snippets/empty-state.html +17 -0
  129. package/snippets/entity-card.html +26 -0
  130. package/snippets/expandable-table.html +26 -0
  131. package/snippets/fact-list.html +14 -0
  132. package/snippets/filter-counts.html +30 -0
  133. package/snippets/flip-card.html +22 -0
  134. package/snippets/form-field.html +6 -0
  135. package/snippets/greeting.html +22 -0
  136. package/snippets/heading.html +14 -0
  137. package/snippets/hover-card.html +18 -0
  138. package/snippets/image-zoom.html +30 -0
  139. package/snippets/input-group.html +10 -0
  140. package/snippets/input.html +5 -0
  141. package/snippets/item.html +26 -0
  142. package/snippets/kbd.html +13 -0
  143. package/snippets/label.html +9 -0
  144. package/snippets/language-select.html +26 -0
  145. package/snippets/launcher-card.html +14 -0
  146. package/snippets/lightbox.html +50 -0
  147. package/snippets/link-arrow.html +10 -0
  148. package/snippets/list-toolbar.html +33 -0
  149. package/snippets/marquee.html +15 -0
  150. package/snippets/media-card.html +28 -0
  151. package/snippets/media-row.html +21 -0
  152. package/snippets/media-thumb.html +12 -0
  153. package/snippets/menubar.html +30 -0
  154. package/snippets/message-thread.html +123 -0
  155. package/snippets/message.html +51 -0
  156. package/snippets/modal.html +15 -0
  157. package/snippets/native-select.html +15 -0
  158. package/snippets/navmenu.html +23 -0
  159. package/snippets/next-teaser.html +15 -0
  160. package/snippets/number-input.html +27 -0
  161. package/snippets/otp-input.html +9 -0
  162. package/snippets/page-header.html +24 -0
  163. package/snippets/pagination.html +6 -0
  164. package/snippets/password-input.html +24 -0
  165. package/snippets/password-requirements.html +30 -0
  166. package/snippets/phone-input.html +22 -0
  167. package/snippets/popover.html +15 -0
  168. package/snippets/price-card.html +34 -0
  169. package/snippets/product-mark.html +13 -0
  170. package/snippets/progress.html +4 -0
  171. package/snippets/project-card.html +23 -0
  172. package/snippets/prose.html +54 -0
  173. package/snippets/radio.html +17 -0
  174. package/snippets/recovery-codes.html +20 -0
  175. package/snippets/resizable.html +16 -0
  176. package/snippets/scroll-area.html +20 -0
  177. package/snippets/search.html +8 -0
  178. package/snippets/segmented.html +11 -0
  179. package/snippets/select.html +7 -0
  180. package/snippets/separator.html +15 -0
  181. package/snippets/severity-card.html +35 -0
  182. package/snippets/sheet.html +32 -0
  183. package/snippets/sidebar-docs.html +24 -0
  184. package/snippets/sidebar.html +55 -0
  185. package/snippets/site-footer.html +6 -0
  186. package/snippets/site-header.html +26 -0
  187. package/snippets/skeleton.html +4 -0
  188. package/snippets/slider.html +17 -0
  189. package/snippets/sortable-row.html +31 -0
  190. package/snippets/spinner.html +14 -0
  191. package/snippets/stack-card.html +17 -0
  192. package/snippets/stack-list.html +16 -0
  193. package/snippets/stat-card.html +24 -0
  194. package/snippets/stepper.html +13 -0
  195. package/snippets/switch.html +6 -0
  196. package/snippets/table-actions.html +39 -0
  197. package/snippets/table-compact.html +24 -0
  198. package/snippets/table.html +29 -0
  199. package/snippets/tabs.html +9 -0
  200. package/snippets/tag-input.html +60 -0
  201. package/snippets/terminal-log.html +23 -0
  202. package/snippets/textarea.html +3 -0
  203. package/snippets/theme-switch.html +6 -0
  204. package/snippets/time-input.html +26 -0
  205. package/snippets/timeline.html +28 -0
  206. package/snippets/toast-stack.html +10 -0
  207. package/snippets/toast.html +36 -0
  208. package/snippets/toc.html +13 -0
  209. package/snippets/toggle-field.html +20 -0
  210. package/snippets/toggle.html +22 -0
  211. package/snippets/tooltip.html +4 -0
  212. package/snippets/top-progress.html +12 -0
  213. package/snippets/tree.html +38 -0
  214. package/snippets/upgrade-banner.html +28 -0
  215. package/snippets/user.html +15 -0
  216. package/snippets/version-banner.html +15 -0
@@ -0,0 +1,75 @@
1
+ /* File: packages/ui/src/parts/forms-affix-input.css
2
+ Map: --affix group (frame on the wrapper) -> inner input -> inline affix (€, %, @) -> states -> --end alignment
3
+ Affix input: extends .oc-input-group with the modifier .oc-input-group--affix.
4
+ The symbol sits INSIDE the field (no grey addon box). Same markup as input-group, one extra class. */
5
+
6
+ /* The wrapper owns the border; children lose theirs. */
7
+ .oc-input-group--affix {
8
+ align-items: center;
9
+ border: 1px solid var(--oc-input);
10
+ border-radius: var(--oc-radius);
11
+ transition: border-color var(--oc-transition-fast), box-shadow var(--oc-transition-fast);
12
+ }
13
+
14
+ .oc-input-group--affix:focus-within {
15
+ border-color: var(--oc-ring);
16
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--oc-ring) 25%, transparent);
17
+ }
18
+
19
+ /* Input: borderless and without its own focus ring (the frame shows focus).
20
+ Selectors repeat .oc-input-group to beat the base :first-child / :last-child radius rules. */
21
+ .oc-input-group.oc-input-group--affix .oc-input {
22
+ border: 0;
23
+ border-radius: var(--oc-radius);
24
+ box-shadow: none;
25
+ min-inline-size: 0;
26
+ }
27
+
28
+ /* Symbol column: same chrome as the Korrekt / OmniaDesk fields (€, %, @, barcode icon).
29
+ A divider separates the symbol from the value. */
30
+ .oc-input-group.oc-input-group--affix .oc-input-addon {
31
+ align-self: stretch;
32
+ display: inline-flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ min-inline-size: 2.25rem;
36
+ padding-inline: 0.5rem;
37
+ border: 0;
38
+ border-inline-end: 1px solid var(--oc-input);
39
+ border-radius: 0;
40
+ background: transparent;
41
+ color: var(--oc-muted-foreground);
42
+ pointer-events: none;
43
+ user-select: none;
44
+ }
45
+
46
+ /* A symbol after the value (rare) gets the divider on its left. */
47
+ .oc-input-group.oc-input-group--affix .oc-input-addon:last-child:not(:first-child) {
48
+ border-inline-end: 0;
49
+ border-inline-start: 1px solid var(--oc-input);
50
+ }
51
+
52
+ .oc-input-group.oc-input-group--affix .oc-input-addon svg {
53
+ inline-size: 1rem;
54
+ block-size: 1rem;
55
+ }
56
+
57
+ /* Numbers (currency, percent) read better right-aligned. */
58
+ .oc-input-group--end .oc-input {
59
+ text-align: end;
60
+ font-variant-numeric: tabular-nums;
61
+ }
62
+
63
+ /* Invalid: modifier, aria-invalid or the browser's own check (type="email", pattern...) after input. */
64
+ .oc-input-group--affix.oc-input-group--error,
65
+ .oc-input-group--affix:has([aria-invalid="true"]),
66
+ .oc-input-group--affix:has(.oc-input:user-invalid) {
67
+ border-color: var(--oc-destructive);
68
+ }
69
+
70
+ /* Disabled: dim the whole frame. */
71
+ .oc-input-group--affix:has(.oc-input:disabled) {
72
+ opacity: 0.5;
73
+ cursor: not-allowed;
74
+ }
75
+ .oc-input-group--affix:has(.oc-input:disabled) .oc-input { opacity: 1; }
@@ -0,0 +1,75 @@
1
+ /* File: packages/ui/src/parts/forms-barcode-input.css
2
+ Map: wrapper (field + preview stacked) -> monospace field -> preview area -> placeholder bars -> code caption -> empty / invalid states
3
+ Barcode input: a field for an EAN/article code and a preview area below it.
4
+ The preview slot shows CSS placeholder bars; put a real <svg>/<canvas> barcode in it if you render one. */
5
+
6
+ /* Wrapper: field on top, preview below. */
7
+ .oc-barcode-input {
8
+ display: grid;
9
+ gap: 0.5rem;
10
+ max-inline-size: 22rem;
11
+ }
12
+
13
+ /* Field: add next to .oc-input, inside the affix group (icon column + value). */
14
+ .oc-barcode-input-field {
15
+ min-inline-size: 0;
16
+ }
17
+
18
+ .oc-barcode-input-field:user-invalid { border-color: var(--oc-destructive); }
19
+
20
+ /* Preview area: light card with the bars and the code text. */
21
+ .oc-barcode-preview {
22
+ display: grid;
23
+ justify-items: center;
24
+ gap: 0.375rem;
25
+ margin: 0;
26
+ padding: 0.75rem 1rem;
27
+ border: 1px dashed var(--oc-border-strong);
28
+ border-radius: var(--oc-radius);
29
+ background: var(--oc-surface);
30
+ }
31
+
32
+ /* Real barcode graphics placed in the slot scale to the preview width. */
33
+ .oc-barcode-preview > svg,
34
+ .oc-barcode-preview > canvas,
35
+ .oc-barcode-preview > img {
36
+ max-inline-size: 100%;
37
+ block-size: auto;
38
+ }
39
+
40
+ /* Placeholder bars: a decorative stripe pattern (not a scannable code). */
41
+ .oc-barcode-preview-bars {
42
+ inline-size: 100%;
43
+ block-size: 3.5rem;
44
+ background: repeating-linear-gradient(
45
+ 90deg,
46
+ var(--oc-foreground) 0 2px,
47
+ transparent 2px 4px,
48
+ var(--oc-foreground) 4px 5px,
49
+ transparent 5px 8px,
50
+ var(--oc-foreground) 8px 11px,
51
+ transparent 11px 12px
52
+ );
53
+ }
54
+
55
+ /* Code text under the bars. */
56
+ .oc-barcode-preview-code {
57
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
58
+ font-size: 0.8rem;
59
+ letter-spacing: 0.2em;
60
+ color: var(--oc-foreground);
61
+ }
62
+
63
+ /* Empty state: faded bars and a hint instead of the code. */
64
+ .oc-barcode-preview--empty .oc-barcode-preview-bars { opacity: 0.15; }
65
+ .oc-barcode-preview--empty .oc-barcode-preview-code {
66
+ font-family: inherit;
67
+ letter-spacing: 0;
68
+ color: var(--oc-muted-foreground);
69
+ }
70
+
71
+ /* Field invalid: the preview border turns red as well. */
72
+ .oc-barcode-input:has(.oc-barcode-input-field:user-invalid) .oc-barcode-preview,
73
+ .oc-barcode-input:has([aria-invalid="true"]) .oc-barcode-preview {
74
+ border-color: var(--oc-destructive);
75
+ }
@@ -0,0 +1,91 @@
1
+ /* File: packages/ui/src/parts/forms-chip-filter.css
2
+ Map: group -> chip (label + hidden checkbox/radio) -> count bubble -> states -> --scroll / --sm
3
+ Chip filter: rounded filter chips. Checkboxes = pick several, radios = pick one.
4
+ :has(input:checked) highlights the chip; no JavaScript. */
5
+
6
+ /* Group: wrapping row of chips. */
7
+ .oc-chip-filter {
8
+ display: flex;
9
+ flex-wrap: wrap;
10
+ gap: 0.5rem;
11
+ margin: 0;
12
+ padding: 0;
13
+ border: 0;
14
+ }
15
+
16
+ /* Chip: pill-shaped label around one input. */
17
+ .oc-chip-filter-item {
18
+ position: relative;
19
+ display: inline-flex;
20
+ align-items: center;
21
+ gap: 0.375rem;
22
+ padding: 0.3rem 0.85rem;
23
+ border: 1px solid var(--oc-border);
24
+ border-radius: 999px;
25
+ background: transparent;
26
+ color: var(--oc-muted-foreground);
27
+ font-size: 0.8rem;
28
+ font-weight: 500;
29
+ white-space: nowrap;
30
+ cursor: pointer;
31
+ user-select: none;
32
+ transition: background var(--oc-transition-fast), color var(--oc-transition-fast), border-color var(--oc-transition-fast);
33
+ }
34
+
35
+ /* Invisible but focusable input. */
36
+ .oc-chip-filter-item input {
37
+ position: absolute;
38
+ inset: 0;
39
+ margin: 0;
40
+ opacity: 0;
41
+ cursor: pointer;
42
+ }
43
+
44
+ .oc-chip-filter-item:hover {
45
+ border-color: var(--oc-border-strong);
46
+ color: var(--oc-foreground);
47
+ }
48
+
49
+ /* Selected: tinted primary background and border. */
50
+ .oc-chip-filter-item:has(input:checked) {
51
+ border-color: var(--oc-primary);
52
+ background: color-mix(in srgb, var(--oc-primary) 14%, transparent);
53
+ color: var(--oc-foreground);
54
+ }
55
+
56
+ .oc-chip-filter-item:has(input:focus-visible) {
57
+ outline: 2px solid var(--oc-ring);
58
+ outline-offset: 2px;
59
+ }
60
+
61
+ .oc-chip-filter-item:has(input:disabled) {
62
+ opacity: 0.45;
63
+ cursor: not-allowed;
64
+ }
65
+
66
+ /* Optional count bubble inside a chip. */
67
+ .oc-chip-filter-count {
68
+ min-inline-size: 1.25rem;
69
+ padding: 0 0.35rem;
70
+ border-radius: 999px;
71
+ background: var(--oc-surface-strong);
72
+ font-size: 0.7rem;
73
+ font-variant-numeric: tabular-nums;
74
+ text-align: center;
75
+ }
76
+
77
+ .oc-chip-filter-item:has(input:checked) .oc-chip-filter-count {
78
+ background: var(--oc-primary);
79
+ color: var(--oc-primary-foreground);
80
+ }
81
+
82
+ /* Scroll: one line that scrolls sideways (mobile toolbars). */
83
+ .oc-chip-filter--scroll {
84
+ flex-wrap: nowrap;
85
+ overflow-x: auto;
86
+ padding-block: 0.25rem;
87
+ scrollbar-width: thin;
88
+ }
89
+
90
+ /* Small chips. */
91
+ .oc-chip-filter--sm .oc-chip-filter-item { padding: 0.15rem 0.6rem; font-size: 0.72rem; }
@@ -0,0 +1,97 @@
1
+ /* File: packages/ui/src/parts/forms-color-select.css
2
+ Map: group (swatch grid) -> option (label + hidden radio) -> swatch -> states -> --list variant (swatch + name) -> --sm
3
+ Color select: pick one color from a set of swatches. Radio inputs inside labels, so keyboard,
4
+ forms and "name" grouping work natively. Each option sets its color with --oc-swatch (an Omnia token). */
5
+
6
+ /* Group: wrapping row of swatches (role="radiogroup"). */
7
+ .oc-color-select {
8
+ display: flex;
9
+ flex-wrap: wrap;
10
+ gap: 0.5rem;
11
+ margin: 0;
12
+ padding: 0;
13
+ border: 0;
14
+ }
15
+
16
+ /* Option: the label around one radio. --oc-swatch is set inline, e.g. style="--oc-swatch: var(--color-red-70)". */
17
+ .oc-color-select-option {
18
+ --oc-swatch: var(--oc-muted);
19
+ position: relative;
20
+ display: inline-flex;
21
+ align-items: center;
22
+ gap: 0.5rem;
23
+ border-radius: 999px;
24
+ color: var(--oc-foreground);
25
+ font-size: 0.875rem;
26
+ cursor: pointer;
27
+ }
28
+
29
+ /* The radio is invisible but stays focusable. */
30
+ .oc-color-select-option input {
31
+ position: absolute;
32
+ inset: 0;
33
+ margin: 0;
34
+ opacity: 0;
35
+ cursor: pointer;
36
+ }
37
+
38
+ /* Swatch: round color dot with a thin inner border so light colors stay visible. */
39
+ .oc-color-select-swatch {
40
+ flex: none;
41
+ inline-size: 1.75rem;
42
+ block-size: 1.75rem;
43
+ border-radius: 999px;
44
+ background: var(--oc-swatch);
45
+ box-shadow: inset 0 0 0 1px oklch(from var(--oc-foreground) l c h / 0.15);
46
+ transition: box-shadow var(--oc-transition-fast), transform var(--oc-transition-fast);
47
+ }
48
+
49
+ .oc-color-select-option:hover .oc-color-select-swatch { transform: scale(1.08); }
50
+
51
+ /* Selected: a ring in the background color, then a ring in the swatch color. */
52
+ .oc-color-select-option:has(input:checked) .oc-color-select-swatch {
53
+ box-shadow: 0 0 0 2px var(--oc-background), 0 0 0 4px var(--oc-swatch);
54
+ }
55
+
56
+ .oc-color-select-option:has(input:focus-visible) .oc-color-select-swatch {
57
+ outline: 2px solid var(--oc-ring);
58
+ outline-offset: 4px;
59
+ }
60
+
61
+ /* Disabled (e.g. a color already in use): faded, a diagonal line through the swatch, no hover zoom.
62
+ Give the label a title ("Purple, in use") so the reason shows on hover. */
63
+ .oc-color-select-option:has(input:disabled) {
64
+ opacity: 0.55;
65
+ cursor: not-allowed;
66
+ }
67
+ .oc-color-select-option:has(input:disabled) .oc-color-select-swatch {
68
+ background:
69
+ linear-gradient(135deg, transparent calc(50% - 1.5px), var(--oc-background) calc(50% - 1.5px) calc(50% + 1.5px), transparent calc(50% + 1.5px)),
70
+ var(--oc-swatch);
71
+ transform: none;
72
+ }
73
+
74
+ /* Name next to the swatch (visible in --list; screen-reader text in the grid). */
75
+ .oc-color-select-name { line-height: 1.2; }
76
+ .oc-color-select:not(.oc-color-select--list) .oc-color-select-name {
77
+ position: absolute;
78
+ inline-size: 1px;
79
+ block-size: 1px;
80
+ overflow: hidden;
81
+ clip-path: inset(50%);
82
+ white-space: nowrap;
83
+ }
84
+
85
+ /* List variant: one row per color with its name, e.g. inside a popover. */
86
+ .oc-color-select--list { flex-direction: column; gap: 0.125rem; }
87
+ .oc-color-select--list .oc-color-select-option {
88
+ padding: 0.375rem 0.5rem;
89
+ border-radius: calc(var(--oc-radius) - 2px);
90
+ }
91
+ .oc-color-select--list .oc-color-select-option:hover { background: var(--oc-surface); }
92
+ .oc-color-select--list .oc-color-select-option:has(input:checked) { background: var(--oc-surface-strong); font-weight: 500; }
93
+ .oc-color-select--list .oc-color-select-swatch { inline-size: 1rem; block-size: 1rem; }
94
+ .oc-color-select--list .oc-color-select-option:hover .oc-color-select-swatch { transform: none; }
95
+
96
+ /* Small swatches. */
97
+ .oc-color-select--sm .oc-color-select-swatch { inline-size: 1.25rem; block-size: 1.25rem; }
@@ -0,0 +1,51 @@
1
+ /* File: packages/ui/src/parts/forms-decimal-input.css
2
+ Map: field (right-aligned tabular digits) -> unit suffix wrapper -> states -> --start alignment
3
+ Decimal input: a text field for locale numbers like 1.234,56 (inputmode="decimal").
4
+ Plain HTML validates with pattern + :user-invalid; the React/Vue wrappers format the value on blur. */
5
+
6
+ /* Field: add next to .oc-input. Digits line up in columns (tabular figures). */
7
+ .oc-decimal-input {
8
+ text-align: end;
9
+ font-variant-numeric: tabular-nums;
10
+ }
11
+
12
+ /* Left-aligned variant, e.g. inside a sentence or a narrow table cell. */
13
+ .oc-decimal-input--start { text-align: start; }
14
+
15
+ /* Wrapper with a unit after the value (m², kg, h). The unit sits inside the frame. */
16
+ .oc-decimal-field {
17
+ display: flex;
18
+ align-items: center;
19
+ border: 1px solid var(--oc-input);
20
+ border-radius: var(--oc-radius);
21
+ transition: border-color var(--oc-transition-fast), box-shadow var(--oc-transition-fast);
22
+ }
23
+
24
+ .oc-decimal-field:focus-within {
25
+ border-color: var(--oc-ring);
26
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--oc-ring) 25%, transparent);
27
+ }
28
+
29
+ /* Inside the wrapper the input has no frame of its own. */
30
+ .oc-decimal-field > .oc-decimal-input {
31
+ flex: 1;
32
+ min-inline-size: 0;
33
+ border: 0;
34
+ box-shadow: none;
35
+ }
36
+
37
+ .oc-decimal-field-unit {
38
+ padding-inline: 0 0.75rem;
39
+ color: var(--oc-muted-foreground);
40
+ font-size: 0.875rem;
41
+ white-space: nowrap;
42
+ pointer-events: none;
43
+ }
44
+
45
+ /* Invalid after user input (pattern mismatch), or via aria-invalid. */
46
+ .oc-decimal-input:user-invalid { border-color: var(--oc-destructive); }
47
+ .oc-decimal-field:has(.oc-decimal-input:user-invalid),
48
+ .oc-decimal-field:has([aria-invalid="true"]) { border-color: var(--oc-destructive); }
49
+
50
+ /* Disabled wrapper. */
51
+ .oc-decimal-field:has(.oc-decimal-input:disabled) { opacity: 0.5; cursor: not-allowed; }
@@ -0,0 +1,94 @@
1
+ /* File: packages/ui/src/parts/forms-filter-counts.css
2
+ Map: group (grid of tiles) -> tile (label + hidden radio) -> value / label / hint -> tones -> states -> --compact
3
+ Filter counts: pick a view (e.g. Active / Deleted / All) from tiles that show how many items each has.
4
+ Radio inputs inside labels; the checked tile gets the accent color. No JavaScript. */
5
+
6
+ /* Group: responsive grid of equal tiles (role="radiogroup"). */
7
+ .oc-filter-counts {
8
+ display: grid;
9
+ grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
10
+ gap: 0.75rem;
11
+ /* A <fieldset> shrinks to its content by default; fill the row so auto-fit can make columns. */
12
+ inline-size: 100%;
13
+ min-inline-size: 0;
14
+ margin: 0;
15
+ padding: 0;
16
+ border: 0;
17
+ }
18
+
19
+ /* Tile: --oc-filter-accent drives the tone (primary by default). */
20
+ .oc-filter-counts-item {
21
+ --oc-filter-accent: var(--oc-primary);
22
+ position: relative;
23
+ display: grid;
24
+ gap: 0.125rem;
25
+ padding: 0.875rem 1rem;
26
+ border: 1px solid var(--oc-border);
27
+ border-radius: var(--oc-radius);
28
+ background: var(--oc-card);
29
+ color: var(--oc-foreground);
30
+ cursor: pointer;
31
+ transition: border-color var(--oc-transition-fast), background var(--oc-transition-fast);
32
+ }
33
+
34
+ /* Invisible but focusable radio. */
35
+ .oc-filter-counts-item input {
36
+ position: absolute;
37
+ inset: 0;
38
+ margin: 0;
39
+ opacity: 0;
40
+ cursor: pointer;
41
+ }
42
+
43
+ .oc-filter-counts-item:hover { background: var(--oc-surface); }
44
+
45
+ /* Big number. */
46
+ .oc-filter-counts-value {
47
+ font-size: 1.5rem;
48
+ font-weight: 700;
49
+ font-variant-numeric: tabular-nums;
50
+ line-height: 1.1;
51
+ color: var(--oc-filter-accent);
52
+ }
53
+
54
+ .oc-filter-counts-label { font-size: 0.875rem; font-weight: 600; }
55
+ .oc-filter-counts-hint { font-size: 0.75rem; color: var(--oc-muted-foreground); }
56
+
57
+ /* Tones per tile. */
58
+ .oc-filter-counts-item--success { --oc-filter-accent: var(--oc-success); }
59
+ .oc-filter-counts-item--destructive { --oc-filter-accent: var(--oc-destructive); }
60
+ .oc-filter-counts-item--muted { --oc-filter-accent: var(--oc-muted-foreground); }
61
+
62
+ /* Selected: accent border + soft accent background. */
63
+ .oc-filter-counts-item:has(input:checked) {
64
+ border-color: var(--oc-filter-accent);
65
+ background: color-mix(in srgb, var(--oc-filter-accent) 10%, var(--oc-card));
66
+ }
67
+
68
+ .oc-filter-counts-item:has(input:focus-visible) {
69
+ outline: 2px solid var(--oc-ring);
70
+ outline-offset: 2px;
71
+ }
72
+
73
+ .oc-filter-counts-item:has(input:disabled) { opacity: 0.5; cursor: not-allowed; }
74
+
75
+ /* Compact: inline pills "Active 12", for toolbars above a table. */
76
+ .oc-filter-counts--compact {
77
+ display: inline-flex;
78
+ inline-size: auto;
79
+ flex-wrap: wrap;
80
+ gap: 0.25rem;
81
+ }
82
+
83
+ .oc-filter-counts--compact .oc-filter-counts-item {
84
+ display: inline-flex;
85
+ flex-direction: row-reverse;
86
+ align-items: baseline;
87
+ gap: 0.375rem;
88
+ padding: 0.3rem 0.75rem;
89
+ border-radius: 999px;
90
+ }
91
+
92
+ .oc-filter-counts--compact .oc-filter-counts-value { font-size: 0.8rem; }
93
+ .oc-filter-counts--compact .oc-filter-counts-label { font-size: 0.8rem; font-weight: 500; }
94
+ .oc-filter-counts--compact .oc-filter-counts-hint { display: none; }
@@ -0,0 +1,89 @@
1
+ /* File: packages/ui/src/parts/forms-language-select.css
2
+ Map: wrapper (icon + native select) -> icon -> select control -> chevron -> states -> --ghost / --currency
3
+ Language select: compact locale (or currency) switcher for a site header.
4
+ A native <select> inside a small frame with a leading icon or symbol. The app reacts to "change". */
5
+
6
+ /* Wrapper: inline frame; the select is stretched over it so the whole pill is clickable. */
7
+ .oc-language-select {
8
+ position: relative;
9
+ display: inline-flex;
10
+ align-items: center;
11
+ gap: 0.375rem;
12
+ padding-inline: 0.625rem 0.5rem;
13
+ border: 1px solid var(--oc-input);
14
+ border-radius: 999px;
15
+ color: var(--oc-foreground);
16
+ font-size: 0.8rem;
17
+ transition: border-color var(--oc-transition-fast), background var(--oc-transition-fast);
18
+ }
19
+
20
+ .oc-language-select:hover { background: var(--oc-surface); }
21
+
22
+ .oc-language-select:focus-within {
23
+ border-color: var(--oc-ring);
24
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--oc-ring) 25%, transparent);
25
+ }
26
+
27
+ /* Leading icon (inline SVG globe) or symbol (€, $). Decorative: aria-hidden="true". */
28
+ .oc-language-select-icon {
29
+ display: inline-flex;
30
+ flex: none;
31
+ inline-size: 1rem;
32
+ justify-content: center;
33
+ color: var(--oc-muted-foreground);
34
+ font-weight: 600;
35
+ }
36
+
37
+ .oc-language-select-icon svg { inline-size: 1rem; block-size: 1rem; }
38
+
39
+ /* Native select without its own frame; room on the right for the chevron. */
40
+ .oc-language-select-control {
41
+ appearance: none;
42
+ padding: 0.375rem 1.25rem 0.375rem 0;
43
+ border: 0;
44
+ background: transparent;
45
+ color: inherit;
46
+ font: inherit;
47
+ cursor: pointer;
48
+ outline: none;
49
+ }
50
+
51
+ .oc-language-select-control option {
52
+ background: var(--oc-background);
53
+ color: var(--oc-foreground);
54
+ }
55
+
56
+ /* Chevron drawn with two borders (no image, follows currentColor). */
57
+ .oc-language-select::after {
58
+ content: "";
59
+ position: absolute;
60
+ inset-inline-end: 0.7rem;
61
+ inset-block-start: 50%;
62
+ inline-size: 0.35rem;
63
+ block-size: 0.35rem;
64
+ border-inline-end: 1.5px solid var(--oc-muted-foreground);
65
+ border-block-end: 1.5px solid var(--oc-muted-foreground);
66
+ transform: translateY(-70%) rotate(45deg);
67
+ pointer-events: none;
68
+ }
69
+
70
+ .oc-language-select:has(.oc-language-select-control:disabled) { opacity: 0.5; cursor: not-allowed; }
71
+
72
+ /* Ghost: no frame, for dense headers and footers. */
73
+ .oc-language-select--ghost { border-color: transparent; }
74
+
75
+ /* Currency: the symbol in the icon slot gets the primary color. */
76
+ .oc-language-select--currency .oc-language-select-icon { color: var(--oc-primary); }
77
+
78
+ /* Menu: the same pill as a <button> that opens an OmniaUI dropdown (popovertarget + .oc-dropdown-menu),
79
+ for a list of links per language. Room on the right for the chevron. */
80
+ button.oc-language-select {
81
+ padding-block: 0.375rem;
82
+ padding-inline-end: 1.6rem;
83
+ background: transparent;
84
+ font: inherit;
85
+ font-size: 0.8rem;
86
+ cursor: pointer;
87
+ outline: none;
88
+ }
89
+ button.oc-language-select:hover { background: var(--oc-surface); }
@@ -0,0 +1,98 @@
1
+ /* File: packages/ui/src/parts/forms-number-input.css
2
+ Map: wrapper -> step buttons (- / +) -> number field (native spinners hidden) -> states -> sizes / block
3
+ Number input: input type="number" between a minus and a plus button.
4
+ The field works on its own (arrow keys, min/max/step); the buttons call stepDown()/stepUp() (tiny script or wrapper). */
5
+
6
+ /* Wrapper: one frame around the buttons and the field. */
7
+ .oc-number-input {
8
+ display: inline-flex;
9
+ align-items: stretch;
10
+ border: 1px solid var(--oc-input);
11
+ border-radius: var(--oc-radius);
12
+ overflow: hidden;
13
+ transition: border-color var(--oc-transition-fast), box-shadow var(--oc-transition-fast);
14
+ }
15
+
16
+ .oc-number-input:focus-within {
17
+ border-color: var(--oc-ring);
18
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--oc-ring) 25%, transparent);
19
+ }
20
+
21
+ /* Step buttons: square, muted, with a divider towards the field. */
22
+ .oc-number-input-step {
23
+ flex: none;
24
+ inline-size: 2.25rem;
25
+ padding: 0;
26
+ border: 0;
27
+ background: var(--oc-surface);
28
+ color: var(--oc-muted-foreground);
29
+ font: inherit;
30
+ font-size: 1rem;
31
+ line-height: 1;
32
+ cursor: pointer;
33
+ transition: background var(--oc-transition-fast), color var(--oc-transition-fast);
34
+ }
35
+
36
+ .oc-number-input-step:first-child { border-inline-end: 1px solid var(--oc-input); }
37
+ .oc-number-input-step:last-child { border-inline-start: 1px solid var(--oc-input); }
38
+
39
+ .oc-number-input-step:hover {
40
+ background: var(--oc-surface-strong);
41
+ color: var(--oc-foreground);
42
+ }
43
+
44
+ .oc-number-input-step:focus-visible {
45
+ outline: 2px solid var(--oc-ring);
46
+ outline-offset: -2px;
47
+ }
48
+
49
+ .oc-number-input-step:disabled {
50
+ opacity: 0.4;
51
+ cursor: not-allowed;
52
+ }
53
+
54
+ /* Field: centered digits, no native spinner arrows (the buttons replace them). */
55
+ .oc-number-input-field {
56
+ inline-size: 4.5rem;
57
+ min-inline-size: 0;
58
+ padding: 0.5rem 0.25rem;
59
+ border: 0;
60
+ background: transparent;
61
+ color: var(--oc-foreground);
62
+ font: inherit;
63
+ font-size: 0.875rem;
64
+ font-variant-numeric: tabular-nums;
65
+ text-align: center;
66
+ outline: none;
67
+ appearance: textfield;
68
+ }
69
+
70
+ .oc-number-input-field::-webkit-inner-spin-button,
71
+ .oc-number-input-field::-webkit-outer-spin-button {
72
+ appearance: none;
73
+ margin: 0;
74
+ }
75
+
76
+ /* Invalid: outside min/max (after user input), aria-invalid or the modifier. */
77
+ .oc-number-input--error,
78
+ .oc-number-input:has([aria-invalid="true"]),
79
+ .oc-number-input:has(.oc-number-input-field:user-invalid) {
80
+ border-color: var(--oc-destructive);
81
+ }
82
+
83
+ /* Disabled: dim the whole control. */
84
+ .oc-number-input:has(.oc-number-input-field:disabled) {
85
+ opacity: 0.5;
86
+ cursor: not-allowed;
87
+ }
88
+
89
+ /* Inside a grid the control keeps its own width (no empty strip next to the +); --block fills the cell. */
90
+ .oc-number-input { justify-self: start; }
91
+
92
+ /* Full width: the field grows, buttons keep their size. */
93
+ .oc-number-input--block { display: flex; inline-size: 100%; justify-self: stretch; }
94
+ .oc-number-input--block .oc-number-input-field { flex: 1; inline-size: auto; }
95
+
96
+ /* Small size. */
97
+ .oc-number-input--sm .oc-number-input-step { inline-size: 1.75rem; font-size: 0.875rem; }
98
+ .oc-number-input--sm .oc-number-input-field { padding-block: 0.25rem; font-size: 0.8rem; inline-size: 3.5rem; }