bareframe 0.1.0 → 0.1.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 (154) hide show
  1. package/README.md +179 -0
  2. package/dist/bareframe.min.js +119 -0
  3. package/dist/components/accordion.js +66 -0
  4. package/dist/components/autocomplete.css +78 -15
  5. package/dist/components/autocomplete.js +220 -10
  6. package/dist/components/avatar.css +129 -17
  7. package/dist/components/avatar.js +47 -10
  8. package/dist/components/breadcrumb.css +63 -17
  9. package/dist/components/breadcrumb.js +140 -5
  10. package/dist/components/button.css +4 -0
  11. package/dist/components/button.js +95 -15
  12. package/dist/components/chart.css +163 -14
  13. package/dist/components/chart.js +59 -4
  14. package/dist/components/checkbox.css +43 -1
  15. package/dist/components/checkbox.js +98 -5
  16. package/dist/components/dialog.css +95 -0
  17. package/dist/components/dialog.js +172 -4
  18. package/dist/components/divider.css +18 -22
  19. package/dist/components/divider.js +31 -3
  20. package/dist/components/drawer.css +68 -18
  21. package/dist/components/drawer.js +84 -4
  22. package/dist/components/edge.css +54 -0
  23. package/dist/components/edge.js +55 -0
  24. package/dist/components/file-upload.css +72 -3
  25. package/dist/components/file-upload.js +186 -4
  26. package/dist/components/input.css +59 -0
  27. package/dist/components/input.js +369 -4
  28. package/dist/components/list.css +11 -0
  29. package/dist/components/list.js +45 -0
  30. package/dist/components/menu.css +20 -0
  31. package/dist/components/menu.js +144 -0
  32. package/dist/components/modal.css +30 -17
  33. package/dist/components/modal.js +68 -4
  34. package/dist/components/nav.css +39 -0
  35. package/dist/components/progress.css +196 -0
  36. package/dist/components/progress.js +304 -0
  37. package/dist/components/radio.css +35 -1
  38. package/dist/components/radio.js +86 -5
  39. package/dist/components/range.css +91 -0
  40. package/dist/components/range.js +250 -0
  41. package/dist/components/select.css +35 -1
  42. package/dist/components/select.js +255 -4
  43. package/dist/components/skeleton.css +108 -21
  44. package/dist/components/skeleton.js +57 -4
  45. package/dist/components/tab.css +9 -1
  46. package/dist/components/tab.js +66 -1
  47. package/dist/components/tag.css +36 -3
  48. package/dist/components/tag.js +32 -0
  49. package/dist/components/toast.css +113 -0
  50. package/dist/components/toast.js +265 -4
  51. package/dist/components/toggle.css +53 -0
  52. package/dist/components/toggle.js +73 -5
  53. package/dist/components/wizard.css +79 -14
  54. package/dist/components/wizard.js +141 -4
  55. package/dist/index.js +5147 -110
  56. package/dist/manifest.json +5 -42
  57. package/dist/themes/aurora.css +47 -0
  58. package/dist/themes/dark.css +12 -2
  59. package/dist/themes/desert.css +37 -0
  60. package/dist/themes/future.css +47 -0
  61. package/dist/themes/layout.css +191 -0
  62. package/dist/themes/light.css +12 -0
  63. package/dist/themes/matrix.css +37 -0
  64. package/dist/themes/modern.css +64 -0
  65. package/dist/themes/nature.css +47 -0
  66. package/dist/themes/nebula.css +37 -0
  67. package/dist/themes/noir.css +37 -0
  68. package/dist/themes/oceanic.css +37 -0
  69. package/dist/themes/retro.css +47 -0
  70. package/dist/themes/simple.css +47 -0
  71. package/dist/themes/sprint.css +12 -0
  72. package/dist/themes/sunrise.css +37 -0
  73. package/dist/themes/system.css +13 -0
  74. package/package.json +9 -2
  75. package/dist/components/alert.css +0 -30
  76. package/dist/components/alert.js +0 -31
  77. package/dist/components/badge.css +0 -30
  78. package/dist/components/badge.js +0 -31
  79. package/dist/components/banner.css +0 -30
  80. package/dist/components/banner.js +0 -31
  81. package/dist/components/bar-chart.css +0 -30
  82. package/dist/components/bar-chart.js +0 -31
  83. package/dist/components/bottom-sheet.css +0 -30
  84. package/dist/components/bottom-sheet.js +0 -31
  85. package/dist/components/button-group.css +0 -30
  86. package/dist/components/button-group.js +0 -31
  87. package/dist/components/chip.css +0 -30
  88. package/dist/components/chip.js +0 -31
  89. package/dist/components/color-picker.css +0 -30
  90. package/dist/components/color-picker.js +0 -31
  91. package/dist/components/context-menu.css +0 -30
  92. package/dist/components/context-menu.js +0 -31
  93. package/dist/components/donut-chart.css +0 -30
  94. package/dist/components/donut-chart.js +0 -31
  95. package/dist/components/expanded-panel.css +0 -30
  96. package/dist/components/expanded-panel.js +0 -31
  97. package/dist/components/footer.css +0 -30
  98. package/dist/components/footer.js +0 -31
  99. package/dist/components/gantt-chart.css +0 -30
  100. package/dist/components/gantt-chart.js +0 -31
  101. package/dist/components/gauge.css +0 -30
  102. package/dist/components/gauge.js +0 -31
  103. package/dist/components/graph.css +0 -30
  104. package/dist/components/graph.js +0 -31
  105. package/dist/components/header.css +0 -30
  106. package/dist/components/header.js +0 -31
  107. package/dist/components/heatmap.css +0 -30
  108. package/dist/components/heatmap.js +0 -31
  109. package/dist/components/line-chart.css +0 -30
  110. package/dist/components/line-chart.js +0 -31
  111. package/dist/components/list-item.css +0 -30
  112. package/dist/components/list-item.js +0 -31
  113. package/dist/components/menu-item.css +0 -30
  114. package/dist/components/menu-item.js +0 -31
  115. package/dist/components/multi-select.css +0 -30
  116. package/dist/components/multi-select.js +0 -31
  117. package/dist/components/notification.css +0 -30
  118. package/dist/components/notification.js +0 -31
  119. package/dist/components/pie-chart.css +0 -30
  120. package/dist/components/pie-chart.js +0 -31
  121. package/dist/components/popover.css +0 -30
  122. package/dist/components/popover.js +0 -31
  123. package/dist/components/progress-bar.css +0 -30
  124. package/dist/components/progress-bar.js +0 -31
  125. package/dist/components/progress-circle.css +0 -30
  126. package/dist/components/progress-circle.js +0 -31
  127. package/dist/components/radio-group.css +0 -30
  128. package/dist/components/radio-group.js +0 -31
  129. package/dist/components/range-slider.css +0 -30
  130. package/dist/components/range-slider.js +0 -31
  131. package/dist/components/rating.css +0 -30
  132. package/dist/components/rating.js +0 -31
  133. package/dist/components/sheet.css +0 -30
  134. package/dist/components/sheet.js +0 -31
  135. package/dist/components/slider.css +0 -30
  136. package/dist/components/slider.js +0 -31
  137. package/dist/components/snackbar.css +0 -30
  138. package/dist/components/snackbar.js +0 -31
  139. package/dist/components/sparkline.css +0 -30
  140. package/dist/components/sparkline.js +0 -31
  141. package/dist/components/stepper.css +0 -30
  142. package/dist/components/stepper.js +0 -31
  143. package/dist/components/switch.css +0 -30
  144. package/dist/components/switch.js +0 -31
  145. package/dist/components/tab-group.css +0 -30
  146. package/dist/components/tab-group.js +0 -31
  147. package/dist/components/textfield.css +0 -30
  148. package/dist/components/textfield.js +0 -31
  149. package/dist/components/tooltip.css +0 -30
  150. package/dist/components/tooltip.js +0 -31
  151. package/dist/components/treemap.css +0 -30
  152. package/dist/components/treemap.js +0 -31
  153. package/dist/components/upload-dropzone.css +0 -30
  154. package/dist/components/upload-dropzone.js +0 -31
@@ -1,11 +1,15 @@
1
1
  class BfModal extends HTMLElement {
2
+ static observedAttributes = ['open', 'label'];
3
+
2
4
  constructor() {
3
5
  super();
4
6
  this.attachShadow({ mode: 'open' });
7
+ this._onBackdropClick = this._onBackdropClick.bind(this);
5
8
  }
6
9
 
7
10
  connectedCallback() {
8
11
  if (this._initialized) {
12
+ this._sync();
9
13
  return;
10
14
  }
11
15
  this._initialized = true;
@@ -18,13 +22,73 @@ class BfModal extends HTMLElement {
18
22
  const root = document.createElement('div');
19
23
  root.className = 'root';
20
24
  root.setAttribute('part', 'root');
21
- root.innerHTML = '<slot></slot>';
25
+ root.innerHTML = `
26
+ <div class="backdrop" part="backdrop"></div>
27
+ <div class="panel" part="panel"><slot></slot></div>
28
+ `;
29
+
30
+ this.shadowRoot.replaceChildren(link, root);
31
+ this._root = root;
32
+ this._backdrop = root.querySelector('.backdrop');
33
+ this._backdrop.addEventListener('click', this._onBackdropClick);
22
34
 
23
- if (!this.innerHTML.trim()) {
24
- root.textContent = 'modal';
35
+ if (!this.textContent?.trim()) {
36
+ this.textContent = 'modal';
25
37
  }
26
38
 
27
- this.shadowRoot.replaceChildren(link, root);
39
+ this._sync();
40
+ }
41
+
42
+ attributeChangedCallback() {
43
+ this._sync();
44
+ }
45
+
46
+ open() {
47
+ this.setAttribute('open', '');
48
+ }
49
+
50
+ close() {
51
+ this.removeAttribute('open');
52
+ }
53
+
54
+ toggle() {
55
+ if (this.hasAttribute('open')) {
56
+ this.close();
57
+ return;
58
+ }
59
+ this.open();
60
+ }
61
+
62
+ _onBackdropClick() {
63
+ if (this.hasAttribute('persistent')) {
64
+ return;
65
+ }
66
+ this.close();
67
+ }
68
+
69
+ _shouldOpenByDefault() {
70
+ return !this.hasAttribute('id');
71
+ }
72
+
73
+ _sync() {
74
+ if (!this._root) {
75
+ return;
76
+ }
77
+
78
+ if (!this.hasAttribute('open') && this._shouldOpenByDefault()) {
79
+ this.setAttribute('open', '');
80
+ return;
81
+ }
82
+
83
+ const isOpen = this.hasAttribute('open');
84
+ this.hidden = !isOpen;
85
+ this._root.setAttribute('data-open', isOpen ? 'true' : 'false');
86
+ this.setAttribute('aria-hidden', String(!isOpen));
87
+ this.setAttribute('role', 'dialog');
88
+ this.setAttribute('aria-modal', 'true');
89
+ if (this.getAttribute('label')) {
90
+ this.setAttribute('aria-label', this.getAttribute('label'));
91
+ }
28
92
  }
29
93
  }
30
94
 
@@ -19,6 +19,10 @@
19
19
  }
20
20
 
21
21
  .root {
22
+ display: flex;
23
+ align-items: center;
24
+ justify-content: space-between;
25
+ gap: var(--bf-nav-padding-x);
22
26
  background: var(--bf-nav-bg);
23
27
  color: var(--bf-nav-color);
24
28
  border-width: var(--bf-nav-border-width);
@@ -28,3 +32,38 @@
28
32
  padding: var(--bf-nav-padding-y) var(--bf-nav-padding-x);
29
33
  transition: var(--bf-nav-transition);
30
34
  }
35
+
36
+ ::slotted([col]),
37
+ ::slotted([nav-col]) {
38
+ display: flex;
39
+ align-items: center;
40
+ gap: var(--bf-nav-padding-x);
41
+ min-width: 0;
42
+ }
43
+
44
+ ::slotted([col]:first-child),
45
+ ::slotted([nav-col]:first-child) {
46
+ justify-content: flex-start;
47
+ flex: 1 1 0;
48
+ }
49
+
50
+ ::slotted([col]:nth-child(2)),
51
+ ::slotted([nav-col]:nth-child(2)) {
52
+ justify-content: center;
53
+ flex: 1 1 0;
54
+ }
55
+
56
+ ::slotted([col]:last-child),
57
+ ::slotted([nav-col]:last-child) {
58
+ justify-content: flex-end;
59
+ flex: 1 1 0;
60
+ }
61
+
62
+ ::slotted([row]),
63
+ ::slotted([nav-row]) {
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: space-between;
67
+ gap: var(--bf-nav-padding-x);
68
+ width: 100%;
69
+ }
@@ -0,0 +1,196 @@
1
+ :host {
2
+ --bf-progress-font: var(--bf-theme-font-family, inherit);
3
+ --bf-progress-bg: var(--bf-theme-progress-bar-bg, var(--bf-theme-surface-2, #e2e8f0));
4
+ --bf-progress-color: var(--bf-theme-progress-bar-color, var(--bf-theme-button-primary-bg, #2563eb));
5
+ --bf-progress-ring-bg: var(--bf-theme-progress-circle-bg, var(--bf-theme-surface-2, #e2e8f0));
6
+ --bf-progress-ring-color: var(--bf-theme-progress-circle-color, var(--bf-theme-button-primary-bg, #2563eb));
7
+ --bf-progress-radius: var(--bf-theme-radius-md, 999px);
8
+ --bf-progress-track-height: 0.7rem;
9
+ --bf-progress-size-sm: 2rem;
10
+ --bf-progress-size-md: 3rem;
11
+ --bf-progress-size-lg: 4rem;
12
+
13
+ display: inline-flex;
14
+ font: var(--bf-progress-font);
15
+ color: var(--bf-theme-text-1, #0f172a);
16
+ }
17
+
18
+ .root {
19
+ display: inline-flex;
20
+ align-items: center;
21
+ gap: 0.5rem;
22
+ }
23
+
24
+ .linear {
25
+ display: inline-block;
26
+ min-width: 8rem;
27
+ }
28
+
29
+ .track {
30
+ width: 100%;
31
+ height: var(--bf-progress-track-height);
32
+ border-radius: var(--bf-progress-radius);
33
+ background: var(--bf-progress-bg);
34
+ overflow: hidden;
35
+ }
36
+
37
+ .fill {
38
+ height: 100%;
39
+ width: 0;
40
+ background: var(--bf-progress-color);
41
+ transition: width 160ms ease;
42
+ }
43
+
44
+ .circular {
45
+ display: none;
46
+ }
47
+
48
+ .circular svg {
49
+ width: var(--bf-progress-size-md);
50
+ height: var(--bf-progress-size-md);
51
+ transform: rotate(-90deg);
52
+ }
53
+
54
+ .ring,
55
+ .meter {
56
+ fill: none;
57
+ stroke-width: 10;
58
+ }
59
+
60
+ .ring {
61
+ stroke: var(--bf-progress-ring-bg);
62
+ }
63
+
64
+ .meter {
65
+ stroke: var(--bf-progress-ring-color);
66
+ stroke-linecap: round;
67
+ transition: stroke-dashoffset 180ms ease;
68
+ }
69
+
70
+ .meta:empty {
71
+ display: none;
72
+ }
73
+
74
+ .root[data-variant='circular'] .linear {
75
+ display: none;
76
+ }
77
+
78
+ .root[data-variant='circular'] .circular {
79
+ display: inline-block;
80
+ }
81
+
82
+ .root[data-variant='striped'] .fill {
83
+ background-image: linear-gradient(
84
+ 45deg,
85
+ rgba(255, 255, 255, 0.25) 25%,
86
+ transparent 25%,
87
+ transparent 50%,
88
+ rgba(255, 255, 255, 0.25) 50%,
89
+ rgba(255, 255, 255, 0.25) 75%,
90
+ transparent 75%,
91
+ transparent
92
+ );
93
+ background-size: 0.9rem 0.9rem;
94
+ }
95
+
96
+ .root[data-tone='primary'] {
97
+ --bf-progress-color: var(--bf-theme-button-primary-bg, #2563eb);
98
+ --bf-progress-ring-color: var(--bf-theme-button-primary-bg, #2563eb);
99
+ }
100
+
101
+ .root[data-tone='secondary'] {
102
+ --bf-progress-color: var(--bf-theme-button-secondary-color, #1d4ed8);
103
+ --bf-progress-ring-color: var(--bf-theme-button-secondary-color, #1d4ed8);
104
+ }
105
+
106
+ .root[data-loading='true'][data-variant='striped'] .fill,
107
+ .root[data-loading='true'][data-loading-variant='stripe'] .fill {
108
+ animation: bf-progress-stripes 700ms linear infinite;
109
+ }
110
+
111
+ .root[data-loading='true'][data-loading-variant='pulse'] .fill {
112
+ animation: bf-progress-pulse 900ms ease-in-out infinite;
113
+ }
114
+
115
+ .root[data-loading='true'][data-loading-variant='bounce'] .fill {
116
+ transform-origin: left center;
117
+ animation: bf-progress-bounce 900ms ease-in-out infinite;
118
+ }
119
+
120
+ .root[data-loading='true'][data-variant='circular'] .circular svg,
121
+ .root[data-loading='true'][data-loading-variant='spin'][data-variant='circular'] .circular svg {
122
+ animation: bf-progress-spin 1s linear infinite;
123
+ }
124
+
125
+ .root[data-loading='true'][data-variant='circular'] .meter {
126
+ animation: bf-progress-meter 1.1s ease-in-out infinite;
127
+ }
128
+
129
+ .root[data-size='sm'] .circular svg {
130
+ width: var(--bf-progress-size-sm);
131
+ height: var(--bf-progress-size-sm);
132
+ }
133
+
134
+ .root[data-size='lg'] .circular svg {
135
+ width: var(--bf-progress-size-lg);
136
+ height: var(--bf-progress-size-lg);
137
+ }
138
+
139
+ @keyframes bf-progress-indeterminate {
140
+ 0% {
141
+ transform: translateX(-120%);
142
+ }
143
+ 100% {
144
+ transform: translateX(260%);
145
+ }
146
+ }
147
+
148
+ @keyframes bf-progress-stripes {
149
+ 0% {
150
+ background-position: 0 0;
151
+ }
152
+ 100% {
153
+ background-position: 0.9rem 0;
154
+ }
155
+ }
156
+
157
+ @keyframes bf-progress-pulse {
158
+ 0%,
159
+ 100% {
160
+ opacity: 1;
161
+ }
162
+ 50% {
163
+ opacity: 0.45;
164
+ }
165
+ }
166
+
167
+ @keyframes bf-progress-bounce {
168
+ 0%,
169
+ 100% {
170
+ transform: scaleX(1);
171
+ }
172
+ 50% {
173
+ transform: scaleX(0.7);
174
+ }
175
+ }
176
+
177
+ @keyframes bf-progress-spin {
178
+ 0% {
179
+ transform: rotate(-90deg);
180
+ }
181
+ 100% {
182
+ transform: rotate(270deg);
183
+ }
184
+ }
185
+
186
+ @keyframes bf-progress-meter {
187
+ 0% {
188
+ stroke-dashoffset: 220;
189
+ }
190
+ 50% {
191
+ stroke-dashoffset: 80;
192
+ }
193
+ 100% {
194
+ stroke-dashoffset: 220;
195
+ }
196
+ }
@@ -0,0 +1,304 @@
1
+ class BfProgress extends HTMLElement {
2
+ static observedAttributes = [
3
+ 'variant',
4
+ 'value',
5
+ 'max',
6
+ 'label',
7
+ 'size',
8
+ 'loading',
9
+ 'loading-variant',
10
+ 'loading-ms',
11
+ 'linear',
12
+ 'circular',
13
+ 'indeterminate',
14
+ 'striped',
15
+ 'tone',
16
+ 'primary',
17
+ 'secondary',
18
+ ];
19
+
20
+ constructor() {
21
+ super();
22
+ this.attachShadow({ mode: 'open' });
23
+ this._onSlotChange = this._onSlotChange.bind(this);
24
+ }
25
+
26
+ connectedCallback() {
27
+ if (this._initialized) {
28
+ this._sync();
29
+ return;
30
+ }
31
+ this._initialized = true;
32
+
33
+ const cssUrl = new URL('./progress.css', import.meta.url);
34
+ const link = document.createElement('link');
35
+ link.rel = 'stylesheet';
36
+ link.href = cssUrl.href;
37
+
38
+ const root = document.createElement('div');
39
+ root.className = 'root';
40
+ root.setAttribute('part', 'root');
41
+ root.innerHTML = `
42
+ <div class="linear" part="linear">
43
+ <div class="track" part="track">
44
+ <div class="fill" part="fill"></div>
45
+ </div>
46
+ </div>
47
+ <div class="circular" part="circular">
48
+ <svg viewBox="0 0 100 100" aria-hidden="true">
49
+ <circle class="ring" cx="50" cy="50" r="42"></circle>
50
+ <circle class="meter" cx="50" cy="50" r="42"></circle>
51
+ </svg>
52
+ </div>
53
+ <div class="meta" part="meta"><slot></slot></div>
54
+ `;
55
+
56
+ this.shadowRoot.replaceChildren(link, root);
57
+ this._root = root;
58
+ this._fill = root.querySelector('.fill');
59
+ this._meter = root.querySelector('.meter');
60
+ this._slot = root.querySelector('slot');
61
+ this._slot.addEventListener('slotchange', this._onSlotChange);
62
+ this._sync();
63
+ }
64
+
65
+ disconnectedCallback() {
66
+ this._stopLoading();
67
+ }
68
+
69
+ attributeChangedCallback() {
70
+ this._sync();
71
+ }
72
+
73
+ get value() {
74
+ return this._value();
75
+ }
76
+
77
+ set value(nextValue) {
78
+ this.setAttribute('value', String(nextValue));
79
+ }
80
+
81
+ get max() {
82
+ return this._max();
83
+ }
84
+
85
+ set max(nextValue) {
86
+ this.setAttribute('max', String(nextValue));
87
+ }
88
+
89
+ get variant() {
90
+ return this._variant();
91
+ }
92
+
93
+ set variant(nextValue) {
94
+ this.setAttribute('variant', String(nextValue));
95
+ }
96
+
97
+ get size() {
98
+ return this.getAttribute('size') || 'md';
99
+ }
100
+
101
+ set size(nextValue) {
102
+ this.setAttribute('size', String(nextValue));
103
+ }
104
+
105
+ get tone() {
106
+ return this._tone();
107
+ }
108
+
109
+ set tone(nextValue) {
110
+ this.setAttribute('tone', String(nextValue));
111
+ }
112
+
113
+ get loading() {
114
+ return this.hasAttribute('loading');
115
+ }
116
+
117
+ set loading(nextValue) {
118
+ if (nextValue) {
119
+ this.setAttribute('loading', '');
120
+ return;
121
+ }
122
+ this.removeAttribute('loading');
123
+ }
124
+
125
+ _onSlotChange() {
126
+ this._renderValueTokens();
127
+ }
128
+
129
+ _variant() {
130
+ let variant = (this.getAttribute('variant') || '').toLowerCase();
131
+ if (!variant) {
132
+ if (this.hasAttribute('circular')) {
133
+ variant = 'circular';
134
+ } else if (this.hasAttribute('striped')) {
135
+ variant = 'striped';
136
+ } else if (this.hasAttribute('linear')) {
137
+ variant = 'linear';
138
+ }
139
+ }
140
+ if (!variant) {
141
+ variant = 'linear';
142
+ }
143
+ if (variant === 'circlular') {
144
+ variant = 'circular';
145
+ }
146
+ if (variant === 'indeterminate') {
147
+ return 'linear';
148
+ }
149
+ if (['linear', 'circular', 'striped'].includes(variant)) {
150
+ return variant;
151
+ }
152
+ return 'linear';
153
+ }
154
+
155
+ _tone() {
156
+ const explicit = (this.getAttribute('tone') || '').toLowerCase();
157
+ if (explicit === 'secondary') {
158
+ return 'secondary';
159
+ }
160
+ if (explicit === 'primary') {
161
+ return 'primary';
162
+ }
163
+ if (this.hasAttribute('secondary')) {
164
+ return 'secondary';
165
+ }
166
+ if (this.hasAttribute('primary')) {
167
+ return 'primary';
168
+ }
169
+ return 'default';
170
+ }
171
+
172
+ _hasMax() {
173
+ return this.hasAttribute('max');
174
+ }
175
+
176
+ _max() {
177
+ const parsed = Number.parseFloat(this.getAttribute('max') || '');
178
+ if (!Number.isFinite(parsed) || parsed <= 0) {
179
+ return 100;
180
+ }
181
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 100;
182
+ }
183
+
184
+ _value() {
185
+ const parsed = Number.parseFloat(this.getAttribute('value') || '0');
186
+ if (!Number.isFinite(parsed)) {
187
+ return 0;
188
+ }
189
+ const upper = this._hasMax() ? this._max() : 100;
190
+ return Math.min(upper, Math.max(0, parsed));
191
+ }
192
+
193
+ _percent() {
194
+ if (!this._hasMax()) {
195
+ return this._value();
196
+ }
197
+ return (this._value() / this._max()) * 100;
198
+ }
199
+
200
+ _loadingVariant() {
201
+ const explicit = (this.getAttribute('loading-variant') || '').toLowerCase();
202
+ const attrValue = (this.getAttribute('loading') || '').toLowerCase();
203
+ const candidate = explicit || attrValue || 'loop';
204
+ if (['loop', 'pulse', 'stripe', 'bounce', 'spin'].includes(candidate)) {
205
+ return candidate;
206
+ }
207
+ return 'loop';
208
+ }
209
+
210
+ _loadingMs() {
211
+ const parsed = Number.parseInt(this.getAttribute('loading-ms') || '450', 10);
212
+ return Number.isFinite(parsed) && parsed >= 80 ? parsed : 450;
213
+ }
214
+
215
+ _isLoading() {
216
+ const legacyVariant = (this.getAttribute('variant') || '').toLowerCase() === 'indeterminate';
217
+ return this.hasAttribute('loading') || this.hasAttribute('indeterminate') || legacyVariant;
218
+ }
219
+
220
+ _startLoading() {
221
+ const ms = this._loadingMs();
222
+ if (this._loadingTimer && this._loadingTimerMs === ms) {
223
+ return;
224
+ }
225
+ this._stopLoading();
226
+ this._loadingTimerMs = ms;
227
+ this._loadingTimer = setInterval(() => {
228
+ const ceiling = this._hasMax() ? this._max() : 100;
229
+ const step = ceiling / 10;
230
+ let next = this._value() + step;
231
+ if (next > ceiling) {
232
+ next = 0;
233
+ }
234
+ this.value = Number(next.toFixed(4));
235
+ }, ms);
236
+ }
237
+
238
+ _stopLoading() {
239
+ if (!this._loadingTimer) {
240
+ return;
241
+ }
242
+ clearInterval(this._loadingTimer);
243
+ this._loadingTimer = null;
244
+ this._loadingTimerMs = null;
245
+ }
246
+
247
+ _formatValueLabel() {
248
+ if (this._hasMax()) {
249
+ return `${Math.round(this._percent())}%`;
250
+ }
251
+ const raw = this._value();
252
+ return Number.isInteger(raw) ? `${raw}` : `${raw.toFixed(2)}`;
253
+ }
254
+
255
+ _renderValueTokens() {
256
+ const tokens = this.querySelectorAll('value');
257
+ if (!tokens.length) {
258
+ return;
259
+ }
260
+ const display = this._formatValueLabel();
261
+ for (const token of tokens) {
262
+ token.textContent = display;
263
+ }
264
+ }
265
+
266
+ _sync() {
267
+ if (!this._root) {
268
+ return;
269
+ }
270
+ const variant = this._variant();
271
+ const percent = this._percent();
272
+ const size = this.getAttribute('size') || 'md';
273
+ const tone = this._tone();
274
+ const loading = this._isLoading();
275
+ const loadingVariant = this._loadingVariant();
276
+
277
+ this._root.setAttribute('data-variant', variant);
278
+ this._root.setAttribute('data-size', size);
279
+ this._root.setAttribute('data-tone', tone);
280
+ this._root.setAttribute('data-loading', loading ? 'true' : 'false');
281
+ this._root.setAttribute('data-loading-variant', loadingVariant);
282
+ this.setAttribute('role', 'progressbar');
283
+ this.setAttribute('aria-valuemin', '0');
284
+ this.setAttribute('aria-valuemax', String(this._hasMax() ? this._max() : 100));
285
+ this.setAttribute('aria-valuenow', String(this._value()));
286
+ if (this.getAttribute('label')) {
287
+ this.setAttribute('aria-label', this.getAttribute('label'));
288
+ }
289
+
290
+ this._fill.style.width = `${percent}%`;
291
+ const circumference = 2 * Math.PI * 42;
292
+ const dash = circumference - (percent / 100) * circumference;
293
+ this._meter.style.strokeDasharray = `${circumference}`;
294
+ this._meter.style.strokeDashoffset = `${dash}`;
295
+ this._renderValueTokens();
296
+ if (loading) {
297
+ this._startLoading();
298
+ } else {
299
+ this._stopLoading();
300
+ }
301
+ }
302
+ }
303
+
304
+ customElements.define('bf-progress', BfProgress);
@@ -13,12 +13,16 @@
13
13
  var(--bf-theme-transition-color, color 120ms ease),
14
14
  var(--bf-theme-transition-border, border-color 120ms ease);
15
15
 
16
- display: block;
16
+ display: inline-block;
17
17
  font: var(--bf-radio-font);
18
18
  color: var(--bf-radio-color);
19
19
  }
20
20
 
21
21
  .root {
22
+ display: inline-flex;
23
+ align-items: center;
24
+ gap: 0.5rem;
25
+ cursor: pointer;
22
26
  background: var(--bf-radio-bg);
23
27
  color: var(--bf-radio-color);
24
28
  border-width: var(--bf-radio-border-width);
@@ -28,3 +32,33 @@
28
32
  padding: var(--bf-radio-padding-y) var(--bf-radio-padding-x);
29
33
  transition: var(--bf-radio-transition);
30
34
  }
35
+
36
+ input {
37
+ position: absolute;
38
+ opacity: 0;
39
+ width: 0;
40
+ height: 0;
41
+ }
42
+
43
+ .dot {
44
+ width: 0.95rem;
45
+ height: 0.95rem;
46
+ border-radius: 999px;
47
+ border: 2px solid var(--bf-radio-border-color);
48
+ display: inline-block;
49
+ position: relative;
50
+ }
51
+
52
+ .dot::after {
53
+ content: '';
54
+ position: absolute;
55
+ inset: 0.15rem;
56
+ border-radius: 999px;
57
+ background: var(--bf-theme-button-primary-bg, #2563eb);
58
+ transform: scale(0);
59
+ transition: transform 120ms ease;
60
+ }
61
+
62
+ input:checked + .dot::after {
63
+ transform: scale(1);
64
+ }