@origostudio/origo-design 0.0.47 → 0.0.48

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 (74) hide show
  1. package/CHANGELOG.md +5 -2
  2. package/dist/packages/angular-renderer/CHANGELOG.md +11 -0
  3. package/dist/packages/angular-renderer/package.json +3 -3
  4. package/dist/packages/angular-renderer/src/components/primitives/button/button.component.d.ts +26 -0
  5. package/dist/packages/angular-renderer/src/components/primitives/button/button.component.js +29 -3
  6. package/dist/packages/angular-renderer/src/components/primitives/button/button.component.js.map +1 -1
  7. package/dist/packages/angular-renderer/src/components/primitives/button-group/button-group.component.d.ts +23 -0
  8. package/dist/packages/angular-renderer/src/components/primitives/button-group/button-group.component.js +73 -0
  9. package/dist/packages/angular-renderer/src/components/primitives/button-group/button-group.component.js.map +1 -0
  10. package/dist/packages/angular-renderer/src/components/primitives/floating-action-button/floating-action-button.component.d.ts +41 -0
  11. package/dist/packages/angular-renderer/src/components/primitives/floating-action-button/floating-action-button.component.js +87 -0
  12. package/dist/packages/angular-renderer/src/components/primitives/floating-action-button/floating-action-button.component.js.map +1 -0
  13. package/dist/packages/angular-renderer/src/components/primitives/icon-button/icon-button.component.d.ts +44 -0
  14. package/dist/packages/angular-renderer/src/components/primitives/icon-button/icon-button.component.js +93 -0
  15. package/dist/packages/angular-renderer/src/components/primitives/icon-button/icon-button.component.js.map +1 -0
  16. package/dist/packages/angular-renderer/src/index.d.ts +3 -0
  17. package/dist/packages/angular-renderer/src/index.js +3 -0
  18. package/dist/packages/angular-renderer/src/index.js.map +1 -1
  19. package/dist/packages/angular-renderer/src/lib/primitives.provider.js +6 -0
  20. package/dist/packages/angular-renderer/src/lib/primitives.provider.js.map +1 -1
  21. package/dist/packages/cli/CHANGELOG.md +4 -0
  22. package/dist/packages/cli/package.json +2 -2
  23. package/dist/packages/cli/package.json.bak +2 -2
  24. package/dist/packages/core/CHANGELOG.md +4 -0
  25. package/dist/packages/core/package.json +1 -1
  26. package/dist/packages/core/package.json.bak +1 -1
  27. package/dist/packages/design-tokens/CHANGELOG.md +4 -0
  28. package/dist/packages/design-tokens/package.json +1 -1
  29. package/dist/packages/playground/browser/{chunk-NvAbwArG.js → chunk-4MD_GCgA.js} +1 -1
  30. package/dist/packages/playground/browser/{chunk-D8xCSUn8.js → chunk-B8F7hD0p.js} +1 -1
  31. package/dist/packages/playground/browser/{chunk-KjK48aB_.js → chunk-BQfPUVzZ.js} +1 -1
  32. package/dist/packages/playground/browser/{chunk-Vi7LKue9.js → chunk-COjGAm8R.js} +1 -1
  33. package/dist/packages/playground/browser/{chunk-hQe37O_T.js → chunk-CQQHYSEg.js} +1 -1
  34. package/dist/packages/playground/browser/{chunk-M-QQ6mOa.js → chunk-CdNbNqNV.js} +1 -1
  35. package/dist/packages/playground/browser/{chunk-Ds2pJNq1.js → chunk-ChP61sze.js} +1 -1
  36. package/dist/packages/playground/browser/{chunk-D8NS9RS7.js → chunk-ClmlG9ZJ.js} +1 -1
  37. package/dist/packages/playground/browser/{chunk-DOh0X2ps.js → chunk-CtaS4wCa.js} +1 -1
  38. package/dist/packages/playground/browser/{chunk-CoC5zYQK.js → chunk-DRRJiw3L.js} +1 -1
  39. package/dist/packages/playground/browser/{chunk-Bnpjwr-7.js → chunk-DvVvDpcg.js} +1 -1
  40. package/dist/packages/playground/browser/{chunk-pi5vOCVu.js → chunk-DyfobgsU.js} +1 -1
  41. package/dist/packages/playground/browser/{chunk-DQXI3hQ7.js → chunk-PT1eAqp3.js} +1 -1
  42. package/dist/packages/playground/browser/{chunk-iW-WwSbU.js → chunk-cI3o8oNy.js} +1 -1
  43. package/dist/packages/playground/browser/{chunk-7aXhMYht.js → chunk-zkDXJCJr.js} +1 -1
  44. package/dist/packages/playground/browser/index.html +1 -1
  45. package/dist/packages/playground/browser/main-DTJJSNK4.js +733 -0
  46. package/package.json +1 -1
  47. package/packages/angular-renderer/CHANGELOG.md +11 -0
  48. package/packages/angular-renderer/package.json +3 -3
  49. package/packages/angular-renderer/src/components/primitives/button/button.component.html +16 -1
  50. package/packages/angular-renderer/src/components/primitives/button/button.component.ts +41 -3
  51. package/packages/angular-renderer/src/components/primitives/button-group/button-group.component.html +8 -0
  52. package/packages/angular-renderer/src/components/primitives/button-group/button-group.component.scss +18 -0
  53. package/packages/angular-renderer/src/components/primitives/button-group/button-group.component.ts +71 -0
  54. package/packages/angular-renderer/src/components/primitives/floating-action-button/floating-action-button.component.html +18 -0
  55. package/packages/angular-renderer/src/components/primitives/floating-action-button/floating-action-button.component.scss +47 -0
  56. package/packages/angular-renderer/src/components/primitives/floating-action-button/floating-action-button.component.ts +94 -0
  57. package/packages/angular-renderer/src/components/primitives/icon-button/icon-button.component.html +18 -0
  58. package/packages/angular-renderer/src/components/primitives/icon-button/icon-button.component.scss +34 -0
  59. package/packages/angular-renderer/src/components/primitives/icon-button/icon-button.component.ts +102 -0
  60. package/packages/angular-renderer/src/index.ts +3 -0
  61. package/packages/angular-renderer/src/lib/primitives.provider.ts +6 -0
  62. package/packages/cli/CHANGELOG.md +4 -0
  63. package/packages/cli/package.json +2 -2
  64. package/packages/core/CHANGELOG.md +4 -0
  65. package/packages/core/package.json +1 -1
  66. package/packages/design-tokens/CHANGELOG.md +4 -0
  67. package/packages/design-tokens/package.json +1 -1
  68. package/packages/devtools/CHANGELOG.md +4 -0
  69. package/packages/devtools/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  70. package/packages/devtools/package.json +3 -3
  71. package/packages/playground/CHANGELOG.md +4 -0
  72. package/packages/playground/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  73. package/packages/playground/package.json +3 -3
  74. package/dist/packages/playground/browser/main-HYTU6AQS.js +0 -731
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@origostudio/origo-design",
3
- "version": "0.0.47",
3
+ "version": "0.0.48",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,3 +1,14 @@
1
+ ## 0.0.48 (2026-10-07)
2
+
3
+ ### 🚀 Features
4
+
5
+ - add core primitives, buttons, and review artifacts for Angular renderer ([f0cbc46](https://github.com/OrigoStudio/origo-design/commit/f0cbc46))
6
+ - add core button and action primitive components to angular-renderer ([2f7d926](https://github.com/OrigoStudio/origo-design/commit/2f7d926))
7
+
8
+ ### ❤️ Thank You
9
+
10
+ - Hardik Patel @hardikpatelse
11
+
1
12
  ## 0.0.47 (2026-10-07)
2
13
 
3
14
  This was a version bump only for angular-renderer to align it with other projects, there were no code changes.
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@origostudio/angular-renderer",
3
- "version": "0.0.47",
3
+ "version": "0.0.48",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "dependencies": {
9
- "@origostudio/core": "0.0.47",
10
- "@origostudio/design-tokens": "0.0.47",
9
+ "@origostudio/core": "0.0.48",
10
+ "@origostudio/design-tokens": "0.0.48",
11
11
  "tslib": "^2.3.0",
12
12
  "@analogjs/vite-plugin-angular": "^2.7.1",
13
13
  "zone.js": "^0.16.3",
@@ -3,7 +3,22 @@
3
3
  [disabled]="computedDisabled()"
4
4
  [attr.aria-label]="computedAriaLabel()"
5
5
  [attr.aria-describedby]="computedAriaDescribedBy()"
6
+ [attr.aria-busy]="computedLoading() ? 'true' : null"
6
7
  (click)="onClick()"
7
8
  >
8
- {{ computedLabel() }}
9
+ @if (computedLoading()) {
10
+ <span class="origo-spinner"></span>
11
+ }
12
+ @if (computedIcon() && computedIconPosition() !== 'right') {
13
+ <span [class]="'origo-icon origo-icon-' + computedIcon()"></span>
14
+ }
15
+ <span class="origo-button-label">{{ computedLabel() }}</span>
16
+ @if (computedBadge()) {
17
+ <span [class]="'origo-badge origo-badge-' + computedBadgeSeverity()">{{
18
+ computedBadge()
19
+ }}</span>
20
+ }
21
+ @if (computedIcon() && computedIconPosition() === 'right') {
22
+ <span [class]="'origo-icon origo-icon-' + computedIcon()"></span>
23
+ }
9
24
  </button>
@@ -17,6 +17,16 @@ export interface ButtonProps {
17
17
  type?: 'button' | 'submit' | 'reset';
18
18
  'aria-label'?: string;
19
19
  'aria-describedby'?: string;
20
+ loading?: boolean;
21
+ severity?: string;
22
+ variant?: string;
23
+ icon?: string;
24
+ iconPosition?: string;
25
+ badge?: string;
26
+ badgeSeverity?: string;
27
+ permissions?: any;
28
+ rules?: any;
29
+ metadata?: any;
20
30
  }
21
31
 
22
32
  @Component({
@@ -27,7 +37,7 @@ export interface ButtonProps {
27
37
  changeDetection: ChangeDetectionStrategy.OnPush,
28
38
  encapsulation: ViewEncapsulation.ShadowDom,
29
39
  host: {
30
- '[class.origo-button]': 'true',
40
+ '[class]': 'computedHostClasses()',
31
41
  '[attr.data-testid]': 'contract().id ?? ""',
32
42
  },
33
43
  })
@@ -36,13 +46,41 @@ export class ButtonComponent implements OrigoAdapter<ButtonProps> {
36
46
  label: 'string',
37
47
  disabled: 'boolean',
38
48
  type: 'string',
49
+ loading: 'boolean',
50
+ severity: 'string',
51
+ variant: 'string',
52
+ icon: 'string',
53
+ iconPosition: 'string',
54
+ badge: 'string',
55
+ badgeSeverity: 'string',
56
+ permissions: 'object',
57
+ rules: 'object',
58
+ metadata: 'object',
39
59
  };
40
60
  static readonly strictContract = false;
41
61
 
42
62
  contract = input.required<InteractionContract<ButtonProps>>();
43
63
 
44
64
  computedLabel = computed(() => this.contract().props?.label ?? 'Button');
45
- computedDisabled = computed(() => !!this.contract().props?.disabled);
65
+ computedLoading = computed(() => !!this.contract().props?.loading);
66
+ computedDisabled = computed(() => {
67
+ const props = this.contract().props;
68
+ const rulesDisable = props?.rules?.disable === true || props?.permissions?.allow === false;
69
+ return !!props?.disabled || this.computedLoading() || rulesDisable;
70
+ });
71
+
72
+ computedIcon = computed(() => this.contract().props?.icon);
73
+ computedIconPosition = computed(() => this.contract().props?.iconPosition ?? 'left');
74
+ computedBadge = computed(() => this.contract().props?.badge);
75
+ computedBadgeSeverity = computed(() => this.contract().props?.badgeSeverity ?? 'info');
76
+
77
+ computedHostClasses = computed(() => {
78
+ const s = this.contract().props?.severity;
79
+ const v = this.contract().props?.variant;
80
+ return ['origo-button', s ? `origo-severity-${s}` : '', v ? `origo-variant-${v}` : '']
81
+ .filter(Boolean)
82
+ .join(' ');
83
+ });
46
84
  computedType = computed(() => {
47
85
  const type = this.contract().props?.type;
48
86
  return type === 'button' || type === 'submit' || type === 'reset' ? type : 'button';
@@ -65,7 +103,7 @@ export class ButtonComponent implements OrigoAdapter<ButtonProps> {
65
103
  private experienceAdapter = inject(WebExperienceAdapterService);
66
104
 
67
105
  onClick() {
68
- if (this.computedDisabled()) return;
106
+ if (this.computedDisabled() || this.computedLoading()) return;
69
107
 
70
108
  const id = this.contract().id;
71
109
  if (!id) return;
@@ -0,0 +1,8 @@
1
+ <div
2
+ class="origo-button-group-content"
3
+ role="group"
4
+ [attr.aria-label]="computedAriaLabel()"
5
+ [attr.aria-describedby]="computedAriaDescribedBy()"
6
+ >
7
+ <ng-content></ng-content>
8
+ </div>
@@ -0,0 +1,18 @@
1
+ :host {
2
+ display: inline-flex;
3
+ }
4
+ .origo-button-group-content {
5
+ display: flex;
6
+ flex-direction: row;
7
+ gap: var(--origo-spacing-container-padding);
8
+ }
9
+ :host(.origo-orientation-column) .origo-button-group-content {
10
+ flex-direction: column;
11
+ }
12
+ :host(.origo-attached) .origo-button-group-content {
13
+ gap: 0;
14
+ }
15
+ /* Note: attached styling across shadow DOM requires passing CSS custom properties to children, which relies on children consuming them. */
16
+ :host(.origo-attached) {
17
+ --origo-button-radius: 0;
18
+ }
@@ -0,0 +1,71 @@
1
+ import {
2
+ Component,
3
+ input,
4
+ ChangeDetectionStrategy,
5
+ computed,
6
+ ViewEncapsulation,
7
+ } from '@angular/core';
8
+ import { InteractionContract } from '@origostudio/core';
9
+ import { OrigoAdapter } from '../../../adapters/web/adapter';
10
+
11
+ export interface ButtonGroupProps {
12
+ orientation?: 'row' | 'column';
13
+ attached?: boolean;
14
+ size?: 'small' | 'medium' | 'large';
15
+ 'aria-label'?: string;
16
+ 'aria-describedby'?: string;
17
+ }
18
+
19
+ @Component({
20
+ selector: 'origo-button-group',
21
+ standalone: true,
22
+ templateUrl: './button-group.component.html',
23
+ styleUrls: ['./button-group.component.scss'],
24
+ changeDetection: ChangeDetectionStrategy.OnPush,
25
+ encapsulation: ViewEncapsulation.ShadowDom,
26
+ host: {
27
+ '[class]': 'computedHostClasses()',
28
+ '[attr.data-testid]': 'contract().id ?? ""',
29
+ },
30
+ })
31
+ export class ButtonGroupComponent implements OrigoAdapter<ButtonGroupProps> {
32
+ static readonly contractSchema = {
33
+ orientation: 'string',
34
+ attached: 'boolean',
35
+ size: 'string',
36
+ 'aria-label': 'string',
37
+ 'aria-describedby': 'string',
38
+ };
39
+ static readonly strictContract = false;
40
+
41
+ contract = input.required<InteractionContract<ButtonGroupProps>>();
42
+
43
+ computedHostClasses = computed(() => {
44
+ const rawO = this.contract().props?.orientation;
45
+ const o = rawO === 'column' ? 'column' : 'row';
46
+ const attached = this.contract().props?.attached;
47
+ const rawSize = this.contract().props?.size;
48
+ const size = ['small', 'medium', 'large'].includes(rawSize as string) ? rawSize : undefined;
49
+ return [
50
+ 'origo-button-group',
51
+ `origo-orientation-${o}`,
52
+ attached ? 'origo-attached' : '',
53
+ size ? `origo-size-${size}` : '',
54
+ ]
55
+ .filter(Boolean)
56
+ .join(' ');
57
+ });
58
+
59
+ computedAriaLabel = computed(() => {
60
+ const label = this.contract().props?.['aria-label'];
61
+ return label !== undefined && label !== null && String(label).trim() !== ''
62
+ ? String(label)
63
+ : undefined;
64
+ });
65
+ computedAriaDescribedBy = computed(() => {
66
+ const desc = this.contract().props?.['aria-describedby'];
67
+ return desc !== undefined && desc !== null && String(desc).trim() !== ''
68
+ ? String(desc)
69
+ : undefined;
70
+ });
71
+ }
@@ -0,0 +1,18 @@
1
+ <button
2
+ type="button"
3
+ [disabled]="computedDisabled()"
4
+ [attr.aria-label]="computedAriaLabel()"
5
+ [attr.aria-describedby]="computedAriaDescribedBy()"
6
+ (click)="onClick()"
7
+ >
8
+ @if (computedLoading()) {
9
+ <span class="origo-spinner"></span>
10
+ } @else {
11
+ @if (computedIcon()) {
12
+ <span [class]="'origo-icon origo-icon-' + computedIcon()"></span>
13
+ }
14
+ }
15
+ @if (computedLabel()) {
16
+ <span class="origo-fab-label">{{ computedLabel() }}</span>
17
+ }
18
+ </button>
@@ -0,0 +1,47 @@
1
+ :host {
2
+ display: inline-flex;
3
+ position: fixed;
4
+ z-index: 1000;
5
+ }
6
+ :host(.origo-position-bottom-right) {
7
+ bottom: var(--origo-spacing-container-padding);
8
+ right: var(--origo-spacing-container-padding);
9
+ }
10
+ :host(.origo-position-bottom-left) {
11
+ bottom: var(--origo-spacing-container-padding);
12
+ left: var(--origo-spacing-container-padding);
13
+ }
14
+ button {
15
+ cursor: pointer;
16
+ background-color: var(--origo-color-surface-primary);
17
+ color: var(--origo-color-text-inverse);
18
+ border: none;
19
+ border-radius: var(--origo-radius-xl);
20
+ box-shadow: var(--origo-shadow-md);
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ gap: var(--origo-spacing-sm, 8px);
25
+ min-width: 48px;
26
+ min-height: 48px;
27
+ padding: 0 var(--origo-spacing-container-padding);
28
+ transition: var(--origo-transition-all);
29
+ }
30
+ button:empty {
31
+ padding: 0;
32
+ }
33
+ button:hover:not(:disabled) {
34
+ background-color: var(--origo-color-surface-primary-hover);
35
+ box-shadow: var(--origo-shadow-lg);
36
+ }
37
+ button:active:not(:disabled) {
38
+ background-color: var(--origo-color-surface-primary-active);
39
+ }
40
+ button:focus-visible {
41
+ outline: var(--origo-outline-width, 2px) solid var(--origo-color-focus);
42
+ outline-offset: var(--origo-outline-width, 2px);
43
+ }
44
+ button:disabled {
45
+ cursor: not-allowed;
46
+ opacity: var(--origo-opacity-disabled);
47
+ }
@@ -0,0 +1,94 @@
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 FabProps {
14
+ icon?: string;
15
+ label?: string;
16
+ severity?: string;
17
+ loading?: boolean;
18
+ disabled?: boolean;
19
+ position?: 'bottom-right' | 'bottom-left';
20
+ 'aria-label'?: string;
21
+ 'aria-describedby'?: string;
22
+ permissions?: any;
23
+ rules?: any;
24
+ metadata?: any;
25
+ }
26
+
27
+ @Component({
28
+ selector: 'origo-fab',
29
+ standalone: true,
30
+ templateUrl: './floating-action-button.component.html',
31
+ styleUrls: ['./floating-action-button.component.scss'],
32
+ changeDetection: ChangeDetectionStrategy.OnPush,
33
+ encapsulation: ViewEncapsulation.ShadowDom,
34
+ host: {
35
+ '[class]': 'computedHostClasses()',
36
+ '[attr.data-testid]': 'contract().id ?? ""',
37
+ },
38
+ })
39
+ export class FloatingActionButtonComponent implements OrigoAdapter<FabProps> {
40
+ static readonly contractSchema = {
41
+ icon: 'string',
42
+ label: 'string',
43
+ severity: 'string',
44
+ loading: 'boolean',
45
+ disabled: 'boolean',
46
+ position: 'string',
47
+ 'aria-label': 'string',
48
+ 'aria-describedby': 'string',
49
+ permissions: 'object',
50
+ rules: 'object',
51
+ metadata: 'object',
52
+ };
53
+ static readonly strictContract = false;
54
+
55
+ contract = input.required<InteractionContract<FabProps>>();
56
+
57
+ computedIcon = computed(() => this.contract().props?.icon ?? '');
58
+ computedLabel = computed(() => this.contract().props?.label ?? '');
59
+ computedLoading = computed(() => !!this.contract().props?.loading);
60
+ computedDisabled = computed(() => {
61
+ const props = this.contract().props;
62
+ const rulesDisable = props?.rules?.disable === true || props?.permissions?.allow === false;
63
+ return !!props?.disabled || this.computedLoading() || rulesDisable;
64
+ });
65
+
66
+ computedAriaLabel = computed(() => {
67
+ const p = this.contract().props;
68
+ const v = p?.['aria-label'] || p?.label;
69
+ return v ? String(v) : undefined;
70
+ });
71
+
72
+ computedAriaDescribedBy = computed(() => {
73
+ const v = this.contract().props?.['aria-describedby'];
74
+ return v ? String(v) : undefined;
75
+ });
76
+
77
+ computedHostClasses = computed(() => {
78
+ const s = this.contract().props?.severity;
79
+ const rawP = this.contract().props?.position;
80
+ const p = ['bottom-left', 'bottom-right'].includes(rawP as string) ? rawP : 'bottom-right';
81
+ return ['origo-fab', s ? `origo-severity-${s}` : '', `origo-position-${p}`]
82
+ .filter(Boolean)
83
+ .join(' ');
84
+ });
85
+
86
+ private experienceAdapter = inject(WebExperienceAdapterService);
87
+
88
+ onClick() {
89
+ if (this.computedDisabled() || this.computedLoading()) return;
90
+ const id = this.contract().id;
91
+ if (!id) return;
92
+ this.experienceAdapter.dispatchCapability(id, 'click');
93
+ }
94
+ }
@@ -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,102 @@
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
+ icon?: string;
15
+ label?: string;
16
+ tooltip?: string;
17
+ severity?: string;
18
+ variant?: string;
19
+ rounded?: boolean;
20
+ loading?: boolean;
21
+ disabled?: boolean;
22
+ 'aria-label'?: string;
23
+ 'aria-describedby'?: string;
24
+ permissions?: any;
25
+ rules?: any;
26
+ metadata?: any;
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
+ icon: 'string',
44
+ label: 'string',
45
+ tooltip: 'string',
46
+ severity: 'string',
47
+ variant: 'string',
48
+ rounded: 'boolean',
49
+ loading: 'boolean',
50
+ disabled: 'boolean',
51
+ 'aria-label': 'string',
52
+ 'aria-describedby': 'string',
53
+ permissions: 'object',
54
+ rules: 'object',
55
+ metadata: 'object',
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 = props?.rules?.disable === true || props?.permissions?.allow === false;
66
+ return !!props?.disabled || this.computedLoading() || rulesDisable;
67
+ });
68
+
69
+ computedAriaLabel = computed(() => {
70
+ const p = this.contract().props;
71
+ const v = p?.['aria-label'] || p?.label;
72
+ return v ? String(v) : undefined;
73
+ });
74
+
75
+ computedAriaDescribedBy = computed(() => {
76
+ const v = this.contract().props?.['aria-describedby'];
77
+ return v ? String(v) : undefined;
78
+ });
79
+
80
+ computedHostClasses = computed(() => {
81
+ const s = this.contract().props?.severity;
82
+ const v = this.contract().props?.variant;
83
+ const rounded = this.contract().props?.rounded;
84
+ return [
85
+ 'origo-icon-button',
86
+ s ? `origo-severity-${s}` : '',
87
+ v ? `origo-variant-${v}` : '',
88
+ rounded ? 'origo-rounded' : '',
89
+ ]
90
+ .filter(Boolean)
91
+ .join(' ');
92
+ });
93
+
94
+ private experienceAdapter = inject(WebExperienceAdapterService);
95
+
96
+ onClick() {
97
+ if (this.computedDisabled() || this.computedLoading()) return;
98
+ const id = this.contract().id;
99
+ if (!id) return;
100
+ this.experienceAdapter.dispatchCapability(id, 'click');
101
+ }
102
+ }
@@ -5,6 +5,9 @@ export * from './adapters/web/adapter';
5
5
  export * from './components/primitives/vbox/vbox.component';
6
6
  export * from './components/primitives/text-input/text-input.component';
7
7
  export * from './components/primitives/button/button.component';
8
+ export * from './components/primitives/icon-button/icon-button.component';
9
+ export * from './components/primitives/button-group/button-group.component';
10
+ export * from './components/primitives/floating-action-button/floating-action-button.component';
8
11
  export * from './devtools';
9
12
  export * from './components/primitives/select/select.component';
10
13
  export * from './components/primitives/checkbox/checkbox.component';
@@ -1,5 +1,8 @@
1
1
  import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';
2
2
  import { RENDERER_REGISTRY } from './renderer.tokens';
3
+ import { IconButtonComponent } from '../components/primitives/icon-button/icon-button.component';
4
+ import { ButtonGroupComponent } from '../components/primitives/button-group/button-group.component';
5
+ import { FloatingActionButtonComponent } from '../components/primitives/floating-action-button/floating-action-button.component';
3
6
  import { SelectComponent } from '../components/primitives/select/select.component';
4
7
  import { CheckboxComponent } from '../components/primitives/checkbox/checkbox.component';
5
8
  import { RadioGroupComponent } from '../components/primitives/radio-group/radio-group.component';
@@ -21,6 +24,9 @@ import { VBoxComponent } from '../components/primitives/vbox/vbox.component';
21
24
 
22
25
  export function provideOrigo9Primitives(): EnvironmentProviders {
23
26
  const registryMap = new Map<string, unknown>([
27
+ ['IconButton', IconButtonComponent],
28
+ ['ButtonGroup', ButtonGroupComponent],
29
+ ['FloatingActionButton', FloatingActionButtonComponent],
24
30
  ['Select', SelectComponent],
25
31
  ['Checkbox', CheckboxComponent],
26
32
  ['RadioGroup', RadioGroupComponent],
@@ -1,3 +1,7 @@
1
+ ## 0.0.48 (2026-10-07)
2
+
3
+ This was a version bump only for cli to align it with other projects, there were no code changes.
4
+
1
5
  ## 0.0.47 (2026-10-07)
2
6
 
3
7
  This was a version bump only for cli to align it with other projects, there were no code changes.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@origostudio/cli",
3
- "version": "0.0.47",
3
+ "version": "0.0.48",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -9,7 +9,7 @@
9
9
  "origo": "./src/main.js"
10
10
  },
11
11
  "dependencies": {
12
- "@origostudio/core": "0.0.47",
12
+ "@origostudio/core": "0.0.48",
13
13
  "commander": "^15.0.0",
14
14
  "tslib": "^2.3.0"
15
15
  },
@@ -1,3 +1,7 @@
1
+ ## 0.0.48 (2026-10-07)
2
+
3
+ This was a version bump only for core to align it with other projects, there were no code changes.
4
+
1
5
  ## 0.0.47 (2026-10-07)
2
6
 
3
7
  This was a version bump only for core to align it with other projects, there were no code changes.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@origostudio/core",
3
- "version": "0.0.47",
3
+ "version": "0.0.48",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -1,3 +1,7 @@
1
+ ## 0.0.48 (2026-10-07)
2
+
3
+ This was a version bump only for design-tokens to align it with other projects, there were no code changes.
4
+
1
5
  ## 0.0.47 (2026-10-07)
2
6
 
3
7
  This was a version bump only for design-tokens to align it with other projects, there were no code changes.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@origostudio/design-tokens",
3
- "version": "0.0.47",
3
+ "version": "0.0.48",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -1,3 +1,7 @@
1
+ ## 0.0.48 (2026-10-07)
2
+
3
+ This was a version bump only for devtools to align it with other projects, there were no code changes.
4
+
1
5
  ## 0.0.47 (2026-10-07)
2
6
 
3
7
  This was a version bump only for devtools to align it with other projects, there were no code changes.
@@ -1 +1 @@
1
- {"version":"4.1.11","results":[[":src/devtools-panel/app.component.spec.ts",{"duration":148.14133299999958,"failed":false}]]}
1
+ {"version":"4.1.11","results":[[":src/devtools-panel/app.component.spec.ts",{"duration":175.88274900000033,"failed":false}]]}