@origostudio/origo-design 0.0.47 → 0.0.49

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 (158) hide show
  1. package/CHANGELOG.md +4 -2
  2. package/apply-fixes.js +18 -0
  3. package/dist/packages/angular-renderer/CHANGELOG.md +22 -0
  4. package/dist/packages/angular-renderer/package.json +3 -3
  5. package/dist/packages/angular-renderer/src/components/primitives/breadcrumbs/breadcrumbs.component.d.ts +6 -0
  6. package/dist/packages/angular-renderer/src/components/primitives/breadcrumbs/breadcrumbs.component.js +3 -0
  7. package/dist/packages/angular-renderer/src/components/primitives/breadcrumbs/breadcrumbs.component.js.map +1 -1
  8. package/dist/packages/angular-renderer/src/components/primitives/button/button.component.d.ts +26 -0
  9. package/dist/packages/angular-renderer/src/components/primitives/button/button.component.js +29 -3
  10. package/dist/packages/angular-renderer/src/components/primitives/button/button.component.js.map +1 -1
  11. package/dist/packages/angular-renderer/src/components/primitives/button-group/button-group.component.d.ts +29 -0
  12. package/dist/packages/angular-renderer/src/components/primitives/button-group/button-group.component.js +76 -0
  13. package/dist/packages/angular-renderer/src/components/primitives/button-group/button-group.component.js.map +1 -0
  14. package/dist/packages/angular-renderer/src/components/primitives/card/card.component.d.ts +6 -0
  15. package/dist/packages/angular-renderer/src/components/primitives/card/card.component.js +3 -0
  16. package/dist/packages/angular-renderer/src/components/primitives/card/card.component.js.map +1 -1
  17. package/dist/packages/angular-renderer/src/components/primitives/checkbox/checkbox.component.d.ts +15 -0
  18. package/dist/packages/angular-renderer/src/components/primitives/checkbox/checkbox.component.js +9 -0
  19. package/dist/packages/angular-renderer/src/components/primitives/checkbox/checkbox.component.js.map +1 -1
  20. package/dist/packages/angular-renderer/src/components/primitives/chip/chip.component.d.ts +3 -0
  21. package/dist/packages/angular-renderer/src/components/primitives/chip/chip.component.js.map +1 -1
  22. package/dist/packages/angular-renderer/src/components/primitives/data-grid/data-grid.component.d.ts +6 -0
  23. package/dist/packages/angular-renderer/src/components/primitives/data-grid/data-grid.component.js +3 -0
  24. package/dist/packages/angular-renderer/src/components/primitives/data-grid/data-grid.component.js.map +1 -1
  25. package/dist/packages/angular-renderer/src/components/primitives/floating-action-button/floating-action-button.component.d.ts +41 -0
  26. package/dist/packages/angular-renderer/src/components/primitives/floating-action-button/floating-action-button.component.js +87 -0
  27. package/dist/packages/angular-renderer/src/components/primitives/floating-action-button/floating-action-button.component.js.map +1 -0
  28. package/dist/packages/angular-renderer/src/components/primitives/form-field/form-field.component.d.ts +6 -0
  29. package/dist/packages/angular-renderer/src/components/primitives/form-field/form-field.component.js +3 -0
  30. package/dist/packages/angular-renderer/src/components/primitives/form-field/form-field.component.js.map +1 -1
  31. package/dist/packages/angular-renderer/src/components/primitives/hbox/hbox.component.d.ts +6 -0
  32. package/dist/packages/angular-renderer/src/components/primitives/hbox/hbox.component.js +3 -0
  33. package/dist/packages/angular-renderer/src/components/primitives/hbox/hbox.component.js.map +1 -1
  34. package/dist/packages/angular-renderer/src/components/primitives/icon-button/icon-button.component.d.ts +44 -0
  35. package/dist/packages/angular-renderer/src/components/primitives/icon-button/icon-button.component.js +93 -0
  36. package/dist/packages/angular-renderer/src/components/primitives/icon-button/icon-button.component.js.map +1 -0
  37. package/dist/packages/angular-renderer/src/components/primitives/input-number/input-number.component.d.ts +46 -0
  38. package/dist/packages/angular-renderer/src/components/primitives/input-number/input-number.component.js +120 -0
  39. package/dist/packages/angular-renderer/src/components/primitives/input-number/input-number.component.js.map +1 -0
  40. package/dist/packages/angular-renderer/src/components/primitives/label/label.component.d.ts +6 -0
  41. package/dist/packages/angular-renderer/src/components/primitives/label/label.component.js +3 -0
  42. package/dist/packages/angular-renderer/src/components/primitives/label/label.component.js.map +1 -1
  43. package/dist/packages/angular-renderer/src/components/primitives/list/list.component.d.ts +6 -0
  44. package/dist/packages/angular-renderer/src/components/primitives/list/list.component.js +3 -0
  45. package/dist/packages/angular-renderer/src/components/primitives/list/list.component.js.map +1 -1
  46. package/dist/packages/angular-renderer/src/components/primitives/radio-group/radio-group.component.d.ts +15 -0
  47. package/dist/packages/angular-renderer/src/components/primitives/radio-group/radio-group.component.js +9 -0
  48. package/dist/packages/angular-renderer/src/components/primitives/radio-group/radio-group.component.js.map +1 -1
  49. package/dist/packages/angular-renderer/src/components/primitives/select/select.component.d.ts +6 -0
  50. package/dist/packages/angular-renderer/src/components/primitives/select/select.component.js +3 -0
  51. package/dist/packages/angular-renderer/src/components/primitives/select/select.component.js.map +1 -1
  52. package/dist/packages/angular-renderer/src/components/primitives/sidebar/sidebar.component.d.ts +6 -0
  53. package/dist/packages/angular-renderer/src/components/primitives/sidebar/sidebar.component.js +3 -0
  54. package/dist/packages/angular-renderer/src/components/primitives/sidebar/sidebar.component.js.map +1 -1
  55. package/dist/packages/angular-renderer/src/components/primitives/switch/switch.component.d.ts +9 -0
  56. package/dist/packages/angular-renderer/src/components/primitives/switch/switch.component.js +6 -0
  57. package/dist/packages/angular-renderer/src/components/primitives/switch/switch.component.js.map +1 -1
  58. package/dist/packages/angular-renderer/src/components/primitives/tabs/tabs.component.d.ts +6 -0
  59. package/dist/packages/angular-renderer/src/components/primitives/tabs/tabs.component.js +3 -0
  60. package/dist/packages/angular-renderer/src/components/primitives/tabs/tabs.component.js.map +1 -1
  61. package/dist/packages/angular-renderer/src/components/primitives/text-input/text-input.component.d.ts +28 -0
  62. package/dist/packages/angular-renderer/src/components/primitives/text-input/text-input.component.js +38 -2
  63. package/dist/packages/angular-renderer/src/components/primitives/text-input/text-input.component.js.map +1 -1
  64. package/dist/packages/angular-renderer/src/components/primitives/textarea/textarea.component.d.ts +26 -0
  65. package/dist/packages/angular-renderer/src/components/primitives/textarea/textarea.component.js +44 -0
  66. package/dist/packages/angular-renderer/src/components/primitives/textarea/textarea.component.js.map +1 -1
  67. package/dist/packages/angular-renderer/src/components/primitives/vbox/vbox.component.d.ts +6 -0
  68. package/dist/packages/angular-renderer/src/components/primitives/vbox/vbox.component.js +3 -0
  69. package/dist/packages/angular-renderer/src/components/primitives/vbox/vbox.component.js.map +1 -1
  70. package/dist/packages/angular-renderer/src/index.d.ts +4 -0
  71. package/dist/packages/angular-renderer/src/index.js +4 -0
  72. package/dist/packages/angular-renderer/src/index.js.map +1 -1
  73. package/dist/packages/angular-renderer/src/lib/primitives.provider.js +8 -0
  74. package/dist/packages/angular-renderer/src/lib/primitives.provider.js.map +1 -1
  75. package/dist/packages/cli/CHANGELOG.md +8 -0
  76. package/dist/packages/cli/package.json +2 -2
  77. package/dist/packages/cli/package.json.bak +2 -2
  78. package/dist/packages/core/CHANGELOG.md +8 -0
  79. package/dist/packages/core/package.json +1 -1
  80. package/dist/packages/core/package.json.bak +1 -1
  81. package/dist/packages/design-tokens/CHANGELOG.md +8 -0
  82. package/dist/packages/design-tokens/package.json +1 -1
  83. package/dist/packages/playground/browser/{chunk-DOh0X2ps.js → chunk-B8mwHWgW.js} +1 -1
  84. package/dist/packages/playground/browser/{chunk-M-QQ6mOa.js → chunk-B_swdRuc.js} +1 -1
  85. package/dist/packages/playground/browser/{chunk-KjK48aB_.js → chunk-BbeNQQ9Z.js} +1 -1
  86. package/dist/packages/playground/browser/{chunk-D8NS9RS7.js → chunk-BlCRDoSd.js} +1 -1
  87. package/dist/packages/playground/browser/{chunk-CoC5zYQK.js → chunk-C8l8Pst_.js} +1 -1
  88. package/dist/packages/playground/browser/{chunk-hQe37O_T.js → chunk-CCE_vAje.js} +1 -1
  89. package/dist/packages/playground/browser/{chunk-7aXhMYht.js → chunk-Cb2ALrKC.js} +1 -1
  90. package/dist/packages/playground/browser/{chunk-NvAbwArG.js → chunk-CpaI4VGh.js} +1 -1
  91. package/dist/packages/playground/browser/{chunk-Ds2pJNq1.js → chunk-DgLZ-dIi.js} +1 -1
  92. package/dist/packages/playground/browser/{chunk-Bnpjwr-7.js → chunk-DkxgAarv.js} +1 -1
  93. package/dist/packages/playground/browser/{chunk-Vi7LKue9.js → chunk-DoYDPF2-.js} +1 -1
  94. package/dist/packages/playground/browser/{chunk-DQXI3hQ7.js → chunk-G1sQXMvG.js} +1 -1
  95. package/dist/packages/playground/browser/{chunk-D8xCSUn8.js → chunk-XTbjIUbx.js} +1 -1
  96. package/dist/packages/playground/browser/{chunk-pi5vOCVu.js → chunk-lFsGUZ3A.js} +1 -1
  97. package/dist/packages/playground/browser/{chunk-iW-WwSbU.js → chunk-r4-UbXQJ.js} +1 -1
  98. package/dist/packages/playground/browser/index.html +1 -1
  99. package/dist/packages/playground/browser/main-D2PNGI4C.js +734 -0
  100. package/package.json +1 -1
  101. package/packages/angular-renderer/CHANGELOG.md +22 -0
  102. package/packages/angular-renderer/package.json +3 -3
  103. package/packages/angular-renderer/src/components/primitives/breadcrumbs/breadcrumbs.component.ts +6 -0
  104. package/packages/angular-renderer/src/components/primitives/button/button.component.html +16 -1
  105. package/packages/angular-renderer/src/components/primitives/button/button.component.ts +42 -3
  106. package/packages/angular-renderer/src/components/primitives/button-group/button-group.component.html +8 -0
  107. package/packages/angular-renderer/src/components/primitives/button-group/button-group.component.scss +18 -0
  108. package/packages/angular-renderer/src/components/primitives/button-group/button-group.component.ts +77 -0
  109. package/packages/angular-renderer/src/components/primitives/card/card.component.ts +6 -0
  110. package/packages/angular-renderer/src/components/primitives/checkbox/checkbox.component.html +24 -15
  111. package/packages/angular-renderer/src/components/primitives/checkbox/checkbox.component.scss +25 -9
  112. package/packages/angular-renderer/src/components/primitives/checkbox/checkbox.component.ts +16 -0
  113. package/packages/angular-renderer/src/components/primitives/chip/chip.component.ts +3 -0
  114. package/packages/angular-renderer/src/components/primitives/data-grid/data-grid.component.ts +6 -0
  115. package/packages/angular-renderer/src/components/primitives/floating-action-button/floating-action-button.component.html +18 -0
  116. package/packages/angular-renderer/src/components/primitives/floating-action-button/floating-action-button.component.scss +47 -0
  117. package/packages/angular-renderer/src/components/primitives/floating-action-button/floating-action-button.component.ts +95 -0
  118. package/packages/angular-renderer/src/components/primitives/form-field/form-field.component.ts +6 -0
  119. package/packages/angular-renderer/src/components/primitives/hbox/hbox.component.ts +6 -0
  120. package/packages/angular-renderer/src/components/primitives/icon-button/icon-button.component.html +18 -0
  121. package/packages/angular-renderer/src/components/primitives/icon-button/icon-button.component.scss +34 -0
  122. package/packages/angular-renderer/src/components/primitives/icon-button/icon-button.component.ts +103 -0
  123. package/packages/angular-renderer/src/components/primitives/input-number/input-number.component.html +24 -0
  124. package/packages/angular-renderer/src/components/primitives/input-number/input-number.component.scss +80 -0
  125. package/packages/angular-renderer/src/components/primitives/input-number/input-number.component.ts +146 -0
  126. package/packages/angular-renderer/src/components/primitives/label/label.component.ts +6 -0
  127. package/packages/angular-renderer/src/components/primitives/list/list.component.ts +6 -0
  128. package/packages/angular-renderer/src/components/primitives/radio-group/radio-group.component.html +11 -1
  129. package/packages/angular-renderer/src/components/primitives/radio-group/radio-group.component.scss +20 -9
  130. package/packages/angular-renderer/src/components/primitives/radio-group/radio-group.component.ts +16 -0
  131. package/packages/angular-renderer/src/components/primitives/select/select.component.ts +6 -0
  132. package/packages/angular-renderer/src/components/primitives/sidebar/sidebar.component.ts +6 -0
  133. package/packages/angular-renderer/src/components/primitives/switch/switch.component.html +24 -15
  134. package/packages/angular-renderer/src/components/primitives/switch/switch.component.scss +40 -22
  135. package/packages/angular-renderer/src/components/primitives/switch/switch.component.ts +13 -0
  136. package/packages/angular-renderer/src/components/primitives/tabs/tabs.component.ts +6 -0
  137. package/packages/angular-renderer/src/components/primitives/text-input/text-input.component.html +21 -10
  138. package/packages/angular-renderer/src/components/primitives/text-input/text-input.component.scss +44 -18
  139. package/packages/angular-renderer/src/components/primitives/text-input/text-input.component.ts +48 -2
  140. package/packages/angular-renderer/src/components/primitives/textarea/textarea.component.html +22 -12
  141. package/packages/angular-renderer/src/components/primitives/textarea/textarea.component.scss +61 -23
  142. package/packages/angular-renderer/src/components/primitives/textarea/textarea.component.ts +58 -0
  143. package/packages/angular-renderer/src/components/primitives/vbox/vbox.component.ts +6 -0
  144. package/packages/angular-renderer/src/index.ts +4 -0
  145. package/packages/angular-renderer/src/lib/primitives.provider.ts +8 -0
  146. package/packages/cli/CHANGELOG.md +8 -0
  147. package/packages/cli/package.json +2 -2
  148. package/packages/core/CHANGELOG.md +8 -0
  149. package/packages/core/package.json +1 -1
  150. package/packages/design-tokens/CHANGELOG.md +8 -0
  151. package/packages/design-tokens/package.json +1 -1
  152. package/packages/devtools/CHANGELOG.md +8 -0
  153. package/packages/devtools/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  154. package/packages/devtools/package.json +3 -3
  155. package/packages/playground/CHANGELOG.md +8 -0
  156. package/packages/playground/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  157. package/packages/playground/package.json +3 -3
  158. package/dist/packages/playground/browser/main-HYTU6AQS.js +0 -731
@@ -11,6 +11,9 @@ import { InteractionContract } from '@origostudio/core';
11
11
  import { OrigoAdapter, ContainerComponent } from '../../../adapters/web/adapter';
12
12
 
13
13
  export interface HBoxProps {
14
+ permissions?: Record<string, string>;
15
+ rules?: Record<string, unknown>;
16
+ metadata?: Record<string, unknown>;
14
17
  gap?: number | string;
15
18
  alignment?: 'start' | 'center' | 'end' | 'stretch';
16
19
  padding?: number | string;
@@ -38,6 +41,9 @@ export interface HBoxProps {
38
41
  })
39
42
  export class HBoxComponent implements OrigoAdapter<HBoxProps>, ContainerComponent {
40
43
  static readonly contractSchema = {
44
+ permissions: 'object',
45
+ rules: 'object',
46
+ metadata: 'object',
41
47
  gap: 'string',
42
48
  alignment: 'string',
43
49
  padding: 'string',
@@ -0,0 +1,18 @@
1
+ <button
2
+ type="button"
3
+ [disabled]="computedDisabled()"
4
+ [attr.aria-label]="computedAriaLabel()"
5
+ [attr.aria-describedby]="computedAriaDescribedBy()"
6
+ [title]="contract().props?.tooltip || null"
7
+ (click)="onClick()"
8
+ >
9
+ @if (computedLoading()) {
10
+ <span class="origo-spinner"></span>
11
+ } @else {
12
+ @if (computedIcon()) {
13
+ <span [class]="'origo-icon origo-icon-' + computedIcon()"></span>
14
+ } @else {
15
+ <span class="origo-icon origo-icon-default"></span>
16
+ }
17
+ }
18
+ </button>
@@ -0,0 +1,34 @@
1
+ :host {
2
+ display: inline-flex;
3
+ }
4
+ button {
5
+ cursor: pointer;
6
+ background-color: var(--origo-color-surface-primary);
7
+ color: var(--origo-color-text-inverse);
8
+ padding: var(--origo-spacing-container-padding);
9
+ border: none;
10
+ border-radius: var(--origo-radius-sm);
11
+ box-shadow: var(--origo-shadow-sm, none);
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ transition: var(--origo-transition-all);
16
+ }
17
+ button:hover:not(:disabled) {
18
+ background-color: var(--origo-color-surface-primary-hover);
19
+ }
20
+ button:active:not(:disabled) {
21
+ background-color: var(--origo-color-surface-primary-active);
22
+ }
23
+ button:focus-visible {
24
+ outline: var(--origo-outline-width, 2px) solid var(--origo-color-focus);
25
+ outline-offset: var(--origo-outline-width, 2px);
26
+ }
27
+ button:disabled {
28
+ cursor: not-allowed;
29
+ opacity: var(--origo-opacity-disabled);
30
+ }
31
+ :host(.origo-rounded) button {
32
+ border-radius: var(--origo-radius-round, 50%);
33
+ aspect-ratio: 1;
34
+ }
@@ -0,0 +1,103 @@
1
+ import {
2
+ Component,
3
+ input,
4
+ ChangeDetectionStrategy,
5
+ computed,
6
+ ViewEncapsulation,
7
+ inject,
8
+ } from '@angular/core';
9
+ import { InteractionContract } from '@origostudio/core';
10
+ import { OrigoAdapter } from '../../../adapters/web/adapter';
11
+ import { WebExperienceAdapterService } from '../../../adapters/web/experience-adapter.service';
12
+
13
+ export interface IconButtonProps {
14
+ permissions?: Record<string, string>;
15
+ rules?: Record<string, unknown>;
16
+ metadata?: Record<string, unknown>;
17
+ icon?: string;
18
+ label?: string;
19
+ tooltip?: string;
20
+ severity?: string;
21
+ variant?: string;
22
+ rounded?: boolean;
23
+ loading?: boolean;
24
+ disabled?: boolean;
25
+ 'aria-label'?: string;
26
+ 'aria-describedby'?: string;
27
+ }
28
+
29
+ @Component({
30
+ selector: 'origo-icon-button',
31
+ standalone: true,
32
+ templateUrl: './icon-button.component.html',
33
+ styleUrls: ['./icon-button.component.scss'],
34
+ changeDetection: ChangeDetectionStrategy.OnPush,
35
+ encapsulation: ViewEncapsulation.ShadowDom,
36
+ host: {
37
+ '[class]': 'computedHostClasses()',
38
+ '[attr.data-testid]': 'contract().id ?? ""',
39
+ },
40
+ })
41
+ export class IconButtonComponent implements OrigoAdapter<IconButtonProps> {
42
+ static readonly contractSchema = {
43
+ permissions: 'object',
44
+ rules: 'object',
45
+ metadata: 'object',
46
+ icon: 'string',
47
+ label: 'string',
48
+ tooltip: 'string',
49
+ severity: 'string',
50
+ variant: 'string',
51
+ rounded: 'boolean',
52
+ loading: 'boolean',
53
+ disabled: 'boolean',
54
+ 'aria-label': 'string',
55
+ 'aria-describedby': 'string',
56
+ };
57
+ static readonly strictContract = false;
58
+
59
+ contract = input.required<InteractionContract<IconButtonProps>>();
60
+
61
+ computedIcon = computed(() => this.contract().props?.icon ?? '');
62
+ computedLoading = computed(() => !!this.contract().props?.loading);
63
+ computedDisabled = computed(() => {
64
+ const props = this.contract().props;
65
+ const rulesDisable =
66
+ props?.rules?.['disable'] === true || props?.permissions?.['allow'] === 'false';
67
+ return !!props?.disabled || this.computedLoading() || rulesDisable;
68
+ });
69
+
70
+ computedAriaLabel = computed(() => {
71
+ const p = this.contract().props;
72
+ const v = p?.['aria-label'] || p?.label;
73
+ return v ? String(v) : undefined;
74
+ });
75
+
76
+ computedAriaDescribedBy = computed(() => {
77
+ const v = this.contract().props?.['aria-describedby'];
78
+ return v ? String(v) : undefined;
79
+ });
80
+
81
+ computedHostClasses = computed(() => {
82
+ const s = this.contract().props?.severity;
83
+ const v = this.contract().props?.variant;
84
+ const rounded = this.contract().props?.rounded;
85
+ return [
86
+ 'origo-icon-button',
87
+ s ? `origo-severity-${s}` : '',
88
+ v ? `origo-variant-${v}` : '',
89
+ rounded ? 'origo-rounded' : '',
90
+ ]
91
+ .filter(Boolean)
92
+ .join(' ');
93
+ });
94
+
95
+ private experienceAdapter = inject(WebExperienceAdapterService);
96
+
97
+ onClick() {
98
+ if (this.computedDisabled() || this.computedLoading()) return;
99
+ const id = this.contract().id;
100
+ if (!id) return;
101
+ this.experienceAdapter.dispatchCapability(id, 'click');
102
+ }
103
+ }
@@ -0,0 +1,24 @@
1
+ <div class="origo-input-number__wrapper">
2
+ <input
3
+ type="number"
4
+ [id]="contract().id"
5
+ [disabled]="computedDisabled()"
6
+ [readonly]="computedReadonly()"
7
+ [required]="computedRequired()"
8
+ [attr.min]="computedMin()"
9
+ [attr.max]="computedMax()"
10
+ [attr.step]="computedStep()"
11
+ [attr.placeholder]="computedPlaceholder()"
12
+ [attr.aria-label]="computedAriaLabel()"
13
+ [attr.aria-describedby]="computedAriaDescribedBy()"
14
+ [attr.aria-invalid]="computedInvalid() ? 'true' : null"
15
+ (input)="onInput($event)"
16
+ [value]="value() ?? ''"
17
+ />
18
+ </div>
19
+ @if (computedErrorText()) {
20
+ <div class="origo-input-number__error">{{ computedErrorText() }}</div>
21
+ }
22
+ @if (computedHelpText()) {
23
+ <div class="origo-input-number__help">{{ computedHelpText() }}</div>
24
+ }
@@ -0,0 +1,80 @@
1
+ :host {
2
+ display: inline-block;
3
+ }
4
+
5
+ :host(.origo-input-number--fluid) {
6
+ display: block;
7
+ width: 100%;
8
+ }
9
+
10
+ .origo-input-number__wrapper {
11
+ display: flex;
12
+ flex-direction: column;
13
+ }
14
+
15
+ input {
16
+ box-sizing: border-box;
17
+ width: 100%;
18
+ background-color: var(--origo-color-surface-background);
19
+ color: var(--origo-color-text-primary);
20
+ padding: var(--origo-spacing-container-padding);
21
+ border: var(--origo-border-width-default) solid var(--origo-color-border-default);
22
+ border-radius: var(--origo-radius-sm);
23
+ box-shadow: var(--origo-shadow-sm);
24
+ font-family: var(--origo-typography-input-font-family);
25
+ font-size: var(--origo-typography-input-font-size);
26
+ font-weight: var(--origo-typography-input-font-weight);
27
+ line-height: var(--origo-typography-input-line-height);
28
+ transition: all var(--origo-duration-fast) ease-in-out;
29
+
30
+ &::placeholder {
31
+ color: var(--origo-color-text-muted);
32
+ }
33
+
34
+ &:hover:not(:disabled):not([readonly]) {
35
+ border-color: var(--origo-color-border-hover);
36
+ }
37
+
38
+ &:active:not(:disabled):not([readonly]) {
39
+ border-color: var(--origo-color-border-active);
40
+ }
41
+
42
+ &:focus,
43
+ &:focus-visible {
44
+ outline: var(--origo-border-width-thick) solid var(--origo-color-focus);
45
+ outline-offset: var(--origo-border-offset-negative);
46
+ border-color: var(--origo-color-focus);
47
+ }
48
+
49
+ &:disabled {
50
+ cursor: not-allowed;
51
+ opacity: var(--origo-opacity-disabled);
52
+ background-color: var(--origo-color-surface-disabled);
53
+ color: var(--origo-color-text-disabled);
54
+ }
55
+
56
+ &[readonly] {
57
+ background-color: var(--origo-color-surface-readonly);
58
+ }
59
+ }
60
+
61
+ :host(.origo-input-number--filled) input {
62
+ background-color: var(--origo-color-surface-subtle);
63
+ border: none;
64
+ }
65
+
66
+ :host(.origo-input-number--text) input {
67
+ background-color: transparent;
68
+ border: none;
69
+ }
70
+
71
+ .origo-input-number__error {
72
+ color: var(--origo-color-text-danger);
73
+ font-size: var(--origo-typography-caption-font-size);
74
+ margin-top: var(--origo-spacing-xs);
75
+ }
76
+ .origo-input-number__help {
77
+ color: var(--origo-color-text-muted);
78
+ font-size: var(--origo-typography-caption-font-size);
79
+ margin-top: var(--origo-spacing-xs);
80
+ }
@@ -0,0 +1,146 @@
1
+ import {
2
+ Component,
3
+ input,
4
+ model,
5
+ ChangeDetectionStrategy,
6
+ computed,
7
+ ViewEncapsulation,
8
+ inject,
9
+ effect,
10
+ untracked,
11
+ SecurityContext,
12
+ } from '@angular/core';
13
+ import { DomSanitizer } from '@angular/platform-browser';
14
+ import { InteractionContract } from '@origostudio/core';
15
+ import { OrigoAdapter, coerceContractProps } from '../../../adapters/web/adapter';
16
+ import { WebExperienceAdapterService } from '../../../adapters/web/experience-adapter.service';
17
+
18
+ export interface InputNumberProps {
19
+ permissions?: Record<string, string>;
20
+ rules?: Record<string, unknown>;
21
+ metadata?: Record<string, unknown>;
22
+ value?: number;
23
+ placeholder?: string;
24
+ disabled?: boolean;
25
+ readonly?: boolean;
26
+ min?: number;
27
+ max?: number;
28
+ step?: number;
29
+ 'aria-label'?: string;
30
+ 'aria-describedby'?: string;
31
+ required?: boolean;
32
+ invalid?: boolean;
33
+ errorText?: string;
34
+ helpText?: string;
35
+ variant?: 'outlined' | 'filled' | 'text';
36
+ fluid?: boolean;
37
+ }
38
+
39
+ @Component({
40
+ selector: 'origo-input-number',
41
+ standalone: true,
42
+ templateUrl: './input-number.component.html',
43
+ styleUrls: ['./input-number.component.scss'],
44
+ changeDetection: ChangeDetectionStrategy.OnPush,
45
+ encapsulation: ViewEncapsulation.ShadowDom,
46
+ host: {
47
+ '[class.origo-input-number]': 'true',
48
+ '[attr.data-testid]': 'contract().id',
49
+ '[class.origo-input-number--fluid]': 'computedFluid()',
50
+ '[class.origo-input-number--outlined]': 'computedVariant() === "outlined"',
51
+ '[class.origo-input-number--filled]': 'computedVariant() === "filled"',
52
+ '[class.origo-input-number--text]': 'computedVariant() === "text"',
53
+ },
54
+ })
55
+ export class InputNumberComponent implements OrigoAdapter<InputNumberProps> {
56
+ static readonly contractSchema: Record<
57
+ string,
58
+ 'string' | 'number' | 'boolean' | 'object' | 'array'
59
+ > = {
60
+ value: 'number',
61
+ placeholder: 'string',
62
+ disabled: 'boolean',
63
+ readonly: 'boolean',
64
+ min: 'number',
65
+ max: 'number',
66
+ step: 'number',
67
+ required: 'boolean',
68
+ invalid: 'boolean',
69
+ errorText: 'string',
70
+ helpText: 'string',
71
+ variant: 'string',
72
+ fluid: 'boolean',
73
+ };
74
+ static readonly strictContract = false;
75
+
76
+ contract = input.required<InteractionContract<InputNumberProps>>();
77
+ value = model<number | undefined>(undefined);
78
+
79
+ computedPlaceholder = computed(() => this.contract().props?.placeholder ?? '');
80
+ computedDisabled = computed(() => !!this.contract().props?.disabled);
81
+ computedReadonly = computed(() => !!this.contract().props?.readonly);
82
+ computedMin = computed(() => this.contract().props?.min);
83
+ computedMax = computed(() => this.contract().props?.max);
84
+ computedStep = computed(() => this.contract().props?.step);
85
+ computedRequired = computed(() => !!this.contract().props?.required);
86
+ computedInvalid = computed(() => !!this.contract().props?.invalid);
87
+ computedVariant = computed(() => this.contract().props?.variant ?? 'outlined');
88
+ computedFluid = computed(() => !!this.contract().props?.fluid);
89
+ computedErrorText = computed(() => this.contract().props?.errorText ?? '');
90
+ computedHelpText = computed(() => this.contract().props?.helpText ?? '');
91
+
92
+ computedAriaLabel = computed(() => {
93
+ const label = this.contract().props?.['aria-label'];
94
+ return label !== undefined && label !== null && String(label).trim() !== ''
95
+ ? String(label)
96
+ : undefined;
97
+ });
98
+ computedAriaDescribedBy = computed(() => {
99
+ const desc = this.contract().props?.['aria-describedby'];
100
+ return desc !== undefined && desc !== null && String(desc).trim() !== ''
101
+ ? String(desc)
102
+ : undefined;
103
+ });
104
+
105
+ private experienceAdapter = inject(WebExperienceAdapterService);
106
+ private sanitizer = inject(DomSanitizer);
107
+
108
+ constructor() {
109
+ effect(() => {
110
+ const props = this.contract().props;
111
+ const coerced = props
112
+ ? coerceContractProps<Record<string, unknown>>(props, InputNumberComponent.contractSchema)
113
+ : {};
114
+ const contractVal = coerced['value'];
115
+
116
+ const parsedVal = typeof contractVal === 'number' ? contractVal : undefined;
117
+ untracked(() => {
118
+ if (parsedVal === this.value()) return;
119
+ this.value.set(parsedVal);
120
+ });
121
+ });
122
+ }
123
+
124
+ onInput(event: Event) {
125
+ const target = event.target as HTMLInputElement | null;
126
+ if (!target || this.computedDisabled() || this.computedReadonly()) return;
127
+
128
+ const rawValue = target.value;
129
+ const sanitizedValue =
130
+ this.sanitizer.sanitize(SecurityContext.HTML, rawValue) || rawValue || '';
131
+
132
+ if (target.value !== sanitizedValue) {
133
+ target.value = sanitizedValue;
134
+ }
135
+
136
+ const numValue = sanitizedValue === '' ? undefined : Number(sanitizedValue);
137
+
138
+ // Check if it's a valid number. If not, don't update state but let the user type
139
+ if (sanitizedValue !== '' && isNaN(Number(sanitizedValue))) {
140
+ return;
141
+ }
142
+
143
+ this.value.set(numValue);
144
+ this.experienceAdapter.updateState(this.contract().id, 'value', numValue);
145
+ }
146
+ }
@@ -9,6 +9,9 @@ import { InteractionContract } from '@origostudio/core';
9
9
  import { OrigoAdapter } from '../../../adapters/web/adapter';
10
10
 
11
11
  export interface LabelProps {
12
+ permissions?: Record<string, string>;
13
+ rules?: Record<string, unknown>;
14
+ metadata?: Record<string, unknown>;
12
15
  text?: string;
13
16
  for?: string;
14
17
  required?: boolean;
@@ -30,6 +33,9 @@ export interface LabelProps {
30
33
  })
31
34
  export class LabelComponent implements OrigoAdapter<LabelProps> {
32
35
  static readonly contractSchema = {
36
+ permissions: 'object',
37
+ rules: 'object',
38
+ metadata: 'object',
33
39
  text: 'string',
34
40
  for: 'string',
35
41
  required: 'boolean',
@@ -13,6 +13,9 @@ import { OrigoAdapter } from '../../../adapters/web/adapter';
13
13
  import { WebExperienceAdapterService } from '../../../adapters/web/experience-adapter.service';
14
14
 
15
15
  export interface ListProps {
16
+ permissions?: Record<string, string>;
17
+ rules?: Record<string, unknown>;
18
+ metadata?: Record<string, unknown>;
16
19
  items?: Array<Record<string, unknown>>;
17
20
  maxItems?: number;
18
21
  disabled?: boolean;
@@ -37,6 +40,9 @@ export interface ListProps {
37
40
  })
38
41
  export class ListComponent implements OrigoAdapter<ListProps> {
39
42
  static readonly contractSchema = {
43
+ permissions: 'object',
44
+ rules: 'object',
45
+ metadata: 'object',
40
46
  items: 'array',
41
47
  maxItems: 'number',
42
48
  disabled: 'boolean',
@@ -1,4 +1,8 @@
1
- <fieldset [disabled]="computedDisabled()" [attr.aria-describedby]="computedAriaDescribedBy()">
1
+ <fieldset
2
+ [disabled]="computedDisabled()"
3
+ [attr.aria-describedby]="computedAriaDescribedBy()"
4
+ [attr.aria-invalid]="computedInvalid() ? 'true' : null"
5
+ >
2
6
  <legend class="visually-hidden">{{ computedAriaLabel() ?? 'Radio Group' }}</legend>
3
7
 
4
8
  <div class="radio-options">
@@ -18,3 +22,9 @@
18
22
  }
19
23
  </div>
20
24
  </fieldset>
25
+ @if (computedErrorText()) {
26
+ <div class="origo-radio-group__error">{{ computedErrorText() }}</div>
27
+ }
28
+ @if (computedHelpText()) {
29
+ <div class="origo-radio-group__help">{{ computedHelpText() }}</div>
30
+ }
@@ -8,7 +8,7 @@ fieldset {
8
8
  margin: 0;
9
9
 
10
10
  &:disabled {
11
- opacity: var(--origo-opacity-disabled, 0.5);
11
+ opacity: var(--origo-opacity-disabled);
12
12
 
13
13
  .radio-label {
14
14
  cursor: not-allowed;
@@ -30,25 +30,36 @@ fieldset {
30
30
  .radio-options {
31
31
  display: flex;
32
32
  flex-direction: column;
33
- gap: var(--origo-spacing-container-padding, 8px);
33
+ gap: var(--origo-spacing-container-padding);
34
34
  }
35
35
 
36
36
  .radio-label {
37
37
  display: inline-flex;
38
38
  align-items: center;
39
- gap: var(--origo-spacing-container-padding, 8px);
39
+ gap: var(--origo-spacing-container-padding);
40
40
  cursor: pointer;
41
- font-family: var(--origo-typography-input-font-family, inherit);
42
- font-size: var(--origo-typography-input-font-size, 1rem);
43
- color: var(--origo-color-text-primary, #333);
41
+ font-family: var(--origo-typography-input-font-family);
42
+ font-size: var(--origo-typography-input-font-size);
43
+ color: var(--origo-color-text-primary);
44
44
  }
45
45
 
46
46
  input[type='radio'] {
47
47
  margin: 0;
48
- accent-color: var(--origo-color-focus, #005fcc);
48
+ accent-color: var(--origo-color-focus);
49
49
 
50
50
  &:focus-visible {
51
- outline: 2px solid var(--origo-color-focus, #005fcc);
52
- outline-offset: 2px;
51
+ outline: var(--origo-border-width-thick) solid var(--origo-color-focus);
52
+ outline-offset: var(--origo-border-width-thick);
53
53
  }
54
54
  }
55
+
56
+ .origo-radio-group__error {
57
+ color: var(--origo-color-text-danger);
58
+ font-size: var(--origo-typography-caption-font-size);
59
+ margin-top: var(--origo-spacing-xs);
60
+ }
61
+ .origo-radio-group__help {
62
+ color: var(--origo-color-text-muted);
63
+ font-size: var(--origo-typography-caption-font-size);
64
+ margin-top: var(--origo-spacing-xs);
65
+ }
@@ -14,12 +14,18 @@ import { OrigoAdapter } from '../../../adapters/web/adapter';
14
14
  import { WebExperienceAdapterService } from '../../../adapters/web/experience-adapter.service';
15
15
 
16
16
  export interface RadioGroupProps {
17
+ permissions?: Record<string, string>;
18
+ rules?: Record<string, unknown>;
19
+ metadata?: Record<string, unknown>;
17
20
  options: Array<{ value: string; label: string }>;
18
21
  value?: string;
19
22
  disabled?: boolean;
20
23
  'aria-label'?: string;
21
24
  'aria-describedby'?: string;
22
25
  required?: boolean;
26
+ invalid?: boolean;
27
+ errorText?: string;
28
+ helpText?: string;
23
29
  }
24
30
 
25
31
  @Component({
@@ -36,10 +42,16 @@ export interface RadioGroupProps {
36
42
  })
37
43
  export class RadioGroupComponent implements OrigoAdapter<RadioGroupProps> {
38
44
  static readonly contractSchema = {
45
+ permissions: 'object',
46
+ rules: 'object',
47
+ metadata: 'object',
39
48
  options: 'array',
40
49
  value: 'string',
41
50
  disabled: 'boolean',
42
51
  required: 'boolean',
52
+ invalid: 'boolean',
53
+ errorText: 'string',
54
+ helpText: 'string',
43
55
  };
44
56
  static readonly strictContract = false;
45
57
 
@@ -65,6 +77,10 @@ export class RadioGroupComponent implements OrigoAdapter<RadioGroupProps> {
65
77
  : undefined;
66
78
  });
67
79
 
80
+ computedInvalid = computed(() => !!this.contract().props?.invalid);
81
+ computedErrorText = computed(() => this.contract().props?.errorText ?? '');
82
+ computedHelpText = computed(() => this.contract().props?.helpText ?? '');
83
+
68
84
  private experienceAdapter = inject(WebExperienceAdapterService);
69
85
 
70
86
  constructor() {
@@ -16,6 +16,9 @@ import { OrigoAdapter } from '../../../adapters/web/adapter';
16
16
  import { WebExperienceAdapterService } from '../../../adapters/web/experience-adapter.service';
17
17
 
18
18
  export interface SelectProps {
19
+ permissions?: Record<string, string>;
20
+ rules?: Record<string, unknown>;
21
+ metadata?: Record<string, unknown>;
19
22
  options: Array<{ value: string; label: string }>;
20
23
  value?: string;
21
24
  disabled?: boolean;
@@ -39,6 +42,9 @@ export interface SelectProps {
39
42
  })
40
43
  export class SelectComponent implements OrigoAdapter<SelectProps> {
41
44
  static readonly contractSchema = {
45
+ permissions: 'object',
46
+ rules: 'object',
47
+ metadata: 'object',
42
48
  options: 'array',
43
49
  value: 'string',
44
50
  disabled: 'boolean',
@@ -20,6 +20,9 @@ export interface SidebarItem {
20
20
  }
21
21
 
22
22
  export interface SidebarProps {
23
+ permissions?: Record<string, string>;
24
+ rules?: Record<string, unknown>;
25
+ metadata?: Record<string, unknown>;
23
26
  items?: Array<SidebarItem>;
24
27
  activeOutcome?: string;
25
28
  collapsed?: boolean;
@@ -45,6 +48,9 @@ export interface SidebarProps {
45
48
  })
46
49
  export class SidebarComponent implements OrigoAdapter<SidebarProps> {
47
50
  static readonly contractSchema = {
51
+ permissions: 'object',
52
+ rules: 'object',
53
+ metadata: 'object',
48
54
  items: 'array',
49
55
  collapsed: 'boolean',
50
56
  };
@@ -1,16 +1,25 @@
1
- <label [for]="contract().id" [class.disabled]="computedDisabled()">
2
- <input
3
- type="checkbox"
4
- role="switch"
5
- [id]="contract().id"
6
- [checked]="checked()"
7
- [disabled]="computedDisabled()"
8
- [attr.aria-checked]="checked().toString()"
9
- [attr.aria-label]="computedAriaLabel() ?? undefined"
10
- [attr.aria-describedby]="computedAriaDescribedBy() ?? undefined"
11
- (change)="onChange($event)"
12
- />
13
- @if (computedLabel()) {
14
- <span class="label-text">{{ computedLabel() }}</span>
1
+ <div class="origo-switch__wrapper">
2
+ <label [for]="contract().id" [class.disabled]="computedDisabled()">
3
+ <input
4
+ type="checkbox"
5
+ role="switch"
6
+ [id]="contract().id"
7
+ [checked]="checked()"
8
+ [disabled]="computedDisabled()"
9
+ [attr.aria-checked]="checked().toString()"
10
+ [attr.aria-label]="computedAriaLabel() ?? undefined"
11
+ [attr.aria-describedby]="computedAriaDescribedBy() ?? undefined"
12
+ [attr.aria-invalid]="computedInvalid() ? 'true' : null"
13
+ (change)="onChange($event)"
14
+ />
15
+ @if (computedLabel()) {
16
+ <span class="label-text">{{ computedLabel() }}</span>
17
+ }
18
+ </label>
19
+ @if (computedErrorText()) {
20
+ <div class="origo-switch__error">{{ computedErrorText() }}</div>
15
21
  }
16
- </label>
22
+ @if (computedHelpText()) {
23
+ <div class="origo-switch__help">{{ computedHelpText() }}</div>
24
+ }
25
+ </div>