committed by
GitHub
138 changed files with 2979 additions and 638 deletions
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Copyright © 2016-2026 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.queue; |
|||
|
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategy; |
|||
|
|||
public interface TbMsgPackProcessingContextFactory { |
|||
|
|||
TbMsgPackProcessingContext create(String queueName, TbRuleEngineSubmitStrategy submitStrategy, boolean skipTimeouts); |
|||
|
|||
@Component |
|||
class DefaultTbMsgPackProcessingContextFactory implements TbMsgPackProcessingContextFactory { |
|||
|
|||
@Override |
|||
public TbMsgPackProcessingContext create(String queueName, TbRuleEngineSubmitStrategy submitStrategy, boolean skipTimeouts) { |
|||
return new TbMsgPackProcessingContext(queueName, submitStrategy, skipTimeouts); |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,281 @@ |
|||
/** |
|||
* Copyright © 2016-2026 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.queue.ruleengine; |
|||
|
|||
import com.google.common.util.concurrent.MoreExecutors; |
|||
import org.junit.jupiter.api.AfterEach; |
|||
import org.junit.jupiter.api.BeforeEach; |
|||
import org.junit.jupiter.api.Test; |
|||
import org.junit.jupiter.api.extension.ExtendWith; |
|||
import org.mockito.InOrder; |
|||
import org.mockito.Mock; |
|||
import org.mockito.junit.jupiter.MockitoExtension; |
|||
import org.thingsboard.common.util.ThingsBoardExecutors; |
|||
import org.thingsboard.common.util.ThingsBoardThreadFactory; |
|||
import org.thingsboard.server.actors.ActorSystemContext; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.msg.TbMsgType; |
|||
import org.thingsboard.server.common.data.queue.ProcessingStrategy; |
|||
import org.thingsboard.server.common.data.queue.ProcessingStrategyType; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.common.data.queue.SubmitStrategy; |
|||
import org.thingsboard.server.common.data.queue.SubmitStrategyType; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
import org.thingsboard.server.common.msg.TbMsgMetaData; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
|||
import org.thingsboard.server.common.stats.StatsFactory; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueMsg; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueMsgHeaders; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.PartitionService; |
|||
import org.thingsboard.server.queue.discovery.QueueKey; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.memory.DefaultInMemoryStorage; |
|||
import org.thingsboard.server.queue.memory.InMemoryStorage; |
|||
import org.thingsboard.server.queue.memory.InMemoryTbQueueConsumer; |
|||
import org.thingsboard.server.queue.provider.TbQueueProducerProvider; |
|||
import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; |
|||
import org.thingsboard.server.service.queue.TbMsgPackProcessingContext; |
|||
import org.thingsboard.server.service.queue.TbMsgPackProcessingContextFactory; |
|||
import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStrategyFactory; |
|||
import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategy; |
|||
import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategyFactory; |
|||
import org.thingsboard.server.service.stats.RuleEngineStatisticsService; |
|||
|
|||
import java.time.Duration; |
|||
import java.util.List; |
|||
import java.util.Set; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.concurrent.ExecutorService; |
|||
import java.util.concurrent.Executors; |
|||
import java.util.concurrent.ScheduledExecutorService; |
|||
import java.util.concurrent.TimeUnit; |
|||
import java.util.concurrent.atomic.AtomicInteger; |
|||
|
|||
import static org.assertj.core.api.Assertions.assertThat; |
|||
import static org.awaitility.Awaitility.await; |
|||
import static org.mockito.ArgumentMatchers.any; |
|||
import static org.mockito.ArgumentMatchers.anyLong; |
|||
import static org.mockito.ArgumentMatchers.eq; |
|||
import static org.mockito.ArgumentMatchers.isNull; |
|||
import static org.mockito.BDDMockito.given; |
|||
import static org.mockito.Mockito.doAnswer; |
|||
import static org.mockito.Mockito.inOrder; |
|||
import static org.mockito.Mockito.spy; |
|||
import static org.mockito.Mockito.when; |
|||
|
|||
@ExtendWith(MockitoExtension.class) |
|||
class RuleEngineConsumerLoopTest { |
|||
|
|||
TenantId tenantId = TenantId.fromUUID(UUID.randomUUID()); |
|||
DeviceId deviceId = new DeviceId(UUID.randomUUID()); |
|||
|
|||
InMemoryStorage storage; |
|||
|
|||
@Mock |
|||
ActorSystemContext actorContext; |
|||
@Mock |
|||
StatsFactory statsFactory; |
|||
@Mock |
|||
TbRuleEngineQueueFactory queueFactory; |
|||
@Mock |
|||
RuleEngineStatisticsService statisticsService; |
|||
@Mock |
|||
TbServiceInfoProvider serviceInfoProvider; |
|||
@Mock |
|||
PartitionService partitionService; |
|||
@Mock |
|||
TbQueueProducerProvider producerProvider; |
|||
@Mock |
|||
TbQueueAdmin queueAdmin; |
|||
@Mock |
|||
TbMsgPackProcessingContextFactory packProcessingContextFactory; |
|||
@Mock |
|||
TbMsgPackProcessingContext packCtx; |
|||
|
|||
Queue mainQueue; |
|||
|
|||
TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>> consumer; |
|||
|
|||
TbRuleEngineConsumerContext ruleEngineConsumerContext; |
|||
TbRuleEngineQueueConsumerManager consumerManager; |
|||
|
|||
ExecutorService consumersExecutor; |
|||
ScheduledExecutorService scheduler; |
|||
ExecutorService mgmtExecutor; |
|||
|
|||
@BeforeEach |
|||
void setup() throws InterruptedException { |
|||
consumersExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer")); |
|||
scheduler = ThingsBoardExecutors.newSingleThreadScheduledExecutor("tb-rule-engine-consumer-scheduler"); |
|||
mgmtExecutor = ThingsBoardExecutors.newWorkStealingPool(1, "tb-rule-engine-mgmt"); |
|||
|
|||
mainQueue = new Queue(); |
|||
mainQueue.setTenantId(TenantId.SYS_TENANT_ID); |
|||
mainQueue.setName("Main"); |
|||
mainQueue.setTopic("tb_rule_engine.main"); |
|||
mainQueue.setPollInterval(25); |
|||
mainQueue.setPartitions(1); |
|||
mainQueue.setConsumerPerPartition(false); |
|||
mainQueue.setPackProcessingTimeout(2000L); |
|||
|
|||
var submitStrategy = new SubmitStrategy(); |
|||
submitStrategy.setType(SubmitStrategyType.BURST); |
|||
submitStrategy.setBatchSize(1000); |
|||
mainQueue.setSubmitStrategy(submitStrategy); |
|||
|
|||
var processingStrategy = new ProcessingStrategy(); |
|||
processingStrategy.setType(ProcessingStrategyType.SKIP_ALL_FAILURES); |
|||
processingStrategy.setRetries(3); |
|||
processingStrategy.setFailurePercentage(0.0); |
|||
processingStrategy.setPauseBetweenRetries(3); |
|||
processingStrategy.setMaxPauseBetweenRetries(3); |
|||
mainQueue.setProcessingStrategy(processingStrategy); |
|||
|
|||
storage = new DefaultInMemoryStorage(); |
|||
|
|||
consumer = spy(new InMemoryTbQueueConsumer<>(storage, mainQueue.getTopic())); |
|||
given(queueFactory.createToRuleEngineMsgConsumer(eq(mainQueue), isNull())).willReturn(consumer); |
|||
|
|||
ruleEngineConsumerContext = new TbRuleEngineConsumerContext( |
|||
actorContext, statsFactory, new TbRuleEngineSubmitStrategyFactory(), new TbRuleEngineProcessingStrategyFactory(), |
|||
queueFactory, statisticsService, serviceInfoProvider, partitionService, producerProvider, queueAdmin |
|||
); |
|||
ruleEngineConsumerContext.setPollDuration(25); |
|||
ruleEngineConsumerContext.setPackProcessingTimeout(2000); |
|||
ruleEngineConsumerContext.setStatsEnabled(false); // true by default
|
|||
ruleEngineConsumerContext.setPrometheusStatsEnabled(false); |
|||
ruleEngineConsumerContext.setTopicDeletionDelayInSec(15); |
|||
ruleEngineConsumerContext.setMgmtThreadPoolSize(12); |
|||
|
|||
// Tell the (mock) context factory to return (mock) message pack context
|
|||
given(packProcessingContextFactory.create( |
|||
eq(mainQueue.getName()), |
|||
any(TbRuleEngineSubmitStrategy.class), |
|||
eq(false) |
|||
)).willAnswer(invocation -> { |
|||
TbRuleEngineSubmitStrategy realStrategy = invocation.getArgument(1); |
|||
when(packCtx.getPendingMap()).thenAnswer(i -> realStrategy.getPendingMap()); |
|||
when(packCtx.getFailedMap()).thenReturn(new ConcurrentHashMap<>()); |
|||
return packCtx; |
|||
}); |
|||
|
|||
// Tell the (mock) context's await() to return 'false' (always timeout) immediately
|
|||
given(packCtx.await(anyLong(), any(TimeUnit.class))).willReturn(false); |
|||
|
|||
consumerManager = TbRuleEngineQueueConsumerManager.create() |
|||
.ctx(ruleEngineConsumerContext) |
|||
.queueKey(new QueueKey(ServiceType.TB_RULE_ENGINE, mainQueue)) |
|||
.consumerExecutor(consumersExecutor) |
|||
.scheduler(scheduler) |
|||
.taskExecutor(mgmtExecutor) |
|||
.packProcessingContextFactory(packProcessingContextFactory) |
|||
.build(); |
|||
} |
|||
|
|||
@AfterEach |
|||
void destroy() { |
|||
MoreExecutors.shutdownAndAwaitTermination(scheduler, Duration.ofSeconds(30)); |
|||
MoreExecutors.shutdownAndAwaitTermination(mgmtExecutor, Duration.ofSeconds(30)); |
|||
MoreExecutors.shutdownAndAwaitTermination(consumersExecutor, Duration.ofSeconds(30)); |
|||
} |
|||
|
|||
@Test |
|||
void consumerLoopTest_verifyOperationsOrder() throws InterruptedException { |
|||
// Create partition
|
|||
var partition = TopicPartitionInfo.builder() |
|||
.tenantId(TenantId.SYS_TENANT_ID) |
|||
.topic(mainQueue.getTopic()) |
|||
.partition(0) |
|||
.myPartition(true) |
|||
.useInternalPartition(false) |
|||
.build(); |
|||
|
|||
// Put 10k messages to the queue
|
|||
for (int i = 0; i < 10_000; i++) { |
|||
var tbMsg = TbMsg.newMsg() |
|||
.type(TbMsgType.POST_TELEMETRY_REQUEST) |
|||
.originator(deviceId) |
|||
.data("{\"temperature\":123}") |
|||
.metaData(TbMsgMetaData.EMPTY) |
|||
.build(); |
|||
|
|||
var toRuleEngineMsg = TransportProtos.ToRuleEngineMsg.newBuilder() |
|||
.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) |
|||
.setTenantIdMSB(tenantId.getId().getMostSignificantBits()) |
|||
.setTbMsgProto(TbMsg.toProto(tbMsg)) |
|||
.addAllRelationTypes(Set.of("Success")) |
|||
.build(); |
|||
|
|||
storage.put(partition.getFullTopicName(), new TbProtoQueueMsg<>(UUID.randomUUID(), toRuleEngineMsg, new DefaultTbQueueMsgHeaders())); |
|||
} |
|||
|
|||
// Count how many polls were made
|
|||
var totalPolls = new AtomicInteger(0); |
|||
var emptyPolls = new AtomicInteger(0); |
|||
doAnswer(invocation -> { |
|||
totalPolls.incrementAndGet(); |
|||
@SuppressWarnings("unchecked") |
|||
var messages = (List<TbQueueMsg>) invocation.callRealMethod(); |
|||
if (messages.isEmpty()) { |
|||
emptyPolls.incrementAndGet(); |
|||
} |
|||
return messages; |
|||
}).when(consumer).poll(mainQueue.getPollInterval()); |
|||
|
|||
// Count how many commits were made
|
|||
var totalCommits = new AtomicInteger(0); |
|||
doAnswer(invocation -> { |
|||
totalCommits.incrementAndGet(); |
|||
return invocation.callRealMethod(); |
|||
}).when(consumer).commit(); |
|||
|
|||
// Initialize consumer
|
|||
consumerManager.init(mainQueue); |
|||
|
|||
// Assign partition to the consumer
|
|||
consumerManager.update(Set.of(partition)); |
|||
|
|||
// Give some time for the consumer to get all messages
|
|||
await().atMost(Duration.ofSeconds(10L)).until(() -> storage.getLagTotal() == 0); |
|||
|
|||
// Stop consumer
|
|||
consumerManager.stop(); |
|||
consumerManager.awaitStop(); |
|||
|
|||
// Determine number of non-empty consumer iterations made, since polling does not stop immediately after consuming all messages and may do a few empty polls
|
|||
int nonEmptyPolls = totalPolls.get() - emptyPolls.get(); |
|||
|
|||
// Verify that there is 10 polls and 10 matching commits
|
|||
// Each poll consumes 1k messages and queue has 10k total, so that means 10k total msgs / 1k msgs per poll = 10 polls
|
|||
assertThat(nonEmptyPolls).isEqualTo(10).isEqualTo(totalCommits.get()); |
|||
|
|||
// Verify that poll-await-commit cycle happened in order with correct await timeout
|
|||
InOrder inOrder = inOrder(consumer, packCtx); |
|||
for (int i = 0; i < nonEmptyPolls; i++) { |
|||
inOrder.verify(consumer).poll(mainQueue.getPollInterval()); |
|||
inOrder.verify(packCtx).await(mainQueue.getPackProcessingTimeout(), TimeUnit.MILLISECONDS); |
|||
inOrder.verify(consumer).commit(); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,99 @@ |
|||
/** |
|||
* Copyright © 2016-2026 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.query; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonInclude; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import io.swagger.v3.oas.annotations.media.ArraySchema; |
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import org.jspecify.annotations.Nullable; |
|||
import org.thingsboard.server.common.data.AttributeScope; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
|
|||
@Schema( |
|||
description = """ |
|||
Contains unique time series and attribute key names discovered from entities matching a query, |
|||
optionally including a sample value for each key.""" |
|||
) |
|||
@JsonInclude(JsonInclude.Include.NON_NULL) |
|||
public record AvailableEntityKeysV2( |
|||
@Schema( |
|||
description = "Set of entity types found among the matched entities.", |
|||
example = "[\"DEVICE\", \"ASSET\"]", |
|||
requiredMode = Schema.RequiredMode.REQUIRED |
|||
) |
|||
Set<EntityType> entityTypes, |
|||
|
|||
@ArraySchema( |
|||
arraySchema = @Schema( |
|||
description = """ |
|||
List of unique time series keys available on the matched entities, sorted alphabetically. |
|||
Omitted when timeseries keys were not requested.""", |
|||
nullable = true |
|||
), |
|||
schema = @Schema(implementation = KeyInfo.class) |
|||
) |
|||
@Nullable List<KeyInfo> timeseries, |
|||
|
|||
@Schema( |
|||
description = """ |
|||
Map of attribute scope to the list of unique attribute keys available on the matched entities. |
|||
Only scopes supported by the matched entity types are included. |
|||
Omitted when attribute keys were not requested or when none of the requested scopes apply to the matched entity types.""", |
|||
nullable = true |
|||
) |
|||
@Nullable Map<AttributeScope, List<KeyInfo>> attributes |
|||
) { |
|||
|
|||
@Schema(description = "Key name with an optional sample value.") |
|||
@JsonInclude(JsonInclude.Include.NON_NULL) |
|||
public record KeyInfo( |
|||
@Schema( |
|||
description = "Key name.", |
|||
example = "temperature", |
|||
requiredMode = Schema.RequiredMode.REQUIRED |
|||
) |
|||
String key, |
|||
|
|||
@Schema( |
|||
description = "Most recent sample value for this key across the matched entities. Omitted when samples were not requested.", |
|||
nullable = true |
|||
) |
|||
@Nullable KeySample sample |
|||
) {} |
|||
|
|||
@Schema(description = "Most recent value and its timestamp.") |
|||
public record KeySample( |
|||
@Schema( |
|||
description = "Timestamp in milliseconds since epoch.", example = "1707000000000", |
|||
requiredMode = Schema.RequiredMode.REQUIRED |
|||
) |
|||
long ts, |
|||
|
|||
@Schema( |
|||
description = "Sample value.", |
|||
example = "23.5", |
|||
requiredMode = Schema.RequiredMode.REQUIRED, |
|||
implementation = Object.class |
|||
) |
|||
JsonNode value |
|||
) {} |
|||
|
|||
} |
|||
@ -1,46 +1,13 @@ |
|||
diff --git a/node_modules/@iplab/ngx-color-picker/fesm2022/iplab-ngx-color-picker.mjs b/node_modules/@iplab/ngx-color-picker/fesm2022/iplab-ngx-color-picker.mjs
|
|||
index a372799..a3d709a 100644
|
|||
index a372799..f64a6f8 100644
|
|||
--- a/node_modules/@iplab/ngx-color-picker/fesm2022/iplab-ngx-color-picker.mjs
|
|||
+++ b/node_modules/@iplab/ngx-color-picker/fesm2022/iplab-ngx-color-picker.mjs
|
|||
@@ -1129,11 +1129,11 @@ class RgbaComponent {
|
|||
this.color.set(newColor); |
|||
@@ -516,7 +516,7 @@ class Color {
|
|||
const s = (color.saturation / 100) * (l <= 1 ? l : 2 - l); |
|||
const value = (l + s) / 2; |
|||
const saturation = (2 * s) / (l + s) || 0; |
|||
- return new Hsva(hue, saturation, value, color.alpha);
|
|||
+ return new Hsva(hue, saturation * 100, value * 100, color.alpha);
|
|||
} |
|||
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: RgbaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } |
|||
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: RgbaComponent, isStandalone: true, selector: "rgba-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isAlphaVisible: { classPropertyName: "isAlphaVisible", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "<div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]*\" min=\"0\" max=\"255\" [value]=\"value?.getRed().toString()\" (inputChange)=\"onInputChange($event, 'R')\" />\r\n @if (labelVisible()) {\r\n <span>R</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]*\" min=\"0\" max=\"255\" [value]=\"value?.getGreen().toString()\" (inputChange)=\"onInputChange($event, 'G')\" />\r\n @if (labelVisible()) {\r\n <span>G</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]*\" min=\"0\" max=\"255\" [value]=\"value?.getBlue().toString()\" (inputChange)=\"onInputChange($event, 'B')\" />\r\n @if (labelVisible()) {\r\n <span>B</span>\r\n }\r\n</div>\r\n@if (isAlphaVisible()) {\r\n <div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]+([\\.,][0-9]{1,2})?\" min=\"0\" max=\"1\" [value]=\"value?.getAlpha(true).toString()\" (inputChange)=\"onInputChange($event, 'A')\" />\r\n @if (labelVisible()) {\r\n <span>A</span>\r\n }\r\n </div>\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], dependencies: [{ kind: "directive", type: ColorPickerInputDirective, selector: "[inputChange]", inputs: ["min", "max"], outputs: ["inputChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|||
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: RgbaComponent, isStandalone: true, selector: "rgba-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isAlphaVisible: { classPropertyName: "isAlphaVisible", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "<div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]*\" min=\"0\" max=\"255\" [value]=\"value?.getRed().toString()\" (inputChange)=\"onInputChange($event, 'R')\" />\r\n @if (labelVisible()) {\r\n <span>R</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]*\" min=\"0\" max=\"255\" [value]=\"value?.getGreen().toString()\" (inputChange)=\"onInputChange($event, 'G')\" />\r\n @if (labelVisible()) {\r\n <span>G</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]*\" min=\"0\" max=\"255\" [value]=\"value?.getBlue().toString()\" (inputChange)=\"onInputChange($event, 'B')\" />\r\n @if (labelVisible()) {\r\n <span>B</span>\r\n }\r\n</div>\r\n@if (isAlphaVisible()) {\r\n <div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]+([\\.,][0-9]{1,2})?\" min=\"0\" max=\"1\" [value]=\"value?.getAlpha(true).toString()\" (inputChange)=\"onInputChange($event, 'A')\" />\r\n @if (labelVisible()) {\r\n <span>A</span>\r\n }\r\n </div>\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], dependencies: [{ kind: "directive", type: ColorPickerInputDirective, selector: "[inputChange]", inputs: ["min", "max"], outputs: ["inputChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|||
} |
|||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: RgbaComponent, decorators: [{ |
|||
type: Component, |
|||
- args: [{ selector: `rgba-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ColorPickerInputDirective], template: "<div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]*\" min=\"0\" max=\"255\" [value]=\"value?.getRed().toString()\" (inputChange)=\"onInputChange($event, 'R')\" />\r\n @if (labelVisible()) {\r\n <span>R</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]*\" min=\"0\" max=\"255\" [value]=\"value?.getGreen().toString()\" (inputChange)=\"onInputChange($event, 'G')\" />\r\n @if (labelVisible()) {\r\n <span>G</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]*\" min=\"0\" max=\"255\" [value]=\"value?.getBlue().toString()\" (inputChange)=\"onInputChange($event, 'B')\" />\r\n @if (labelVisible()) {\r\n <span>B</span>\r\n }\r\n</div>\r\n@if (isAlphaVisible()) {\r\n <div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]+([\\.,][0-9]{1,2})?\" min=\"0\" max=\"1\" [value]=\"value?.getAlpha(true).toString()\" (inputChange)=\"onInputChange($event, 'A')\" />\r\n @if (labelVisible()) {\r\n <span>A</span>\r\n }\r\n </div>\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
|
|||
+ args: [{ selector: `rgba-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ColorPickerInputDirective], template: "<div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]*\" min=\"0\" max=\"255\" [value]=\"value?.getRed().toString()\" (inputChange)=\"onInputChange($event, 'R')\" />\r\n @if (labelVisible()) {\r\n <span>R</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]*\" min=\"0\" max=\"255\" [value]=\"value?.getGreen().toString()\" (inputChange)=\"onInputChange($event, 'G')\" />\r\n @if (labelVisible()) {\r\n <span>G</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]*\" min=\"0\" max=\"255\" [value]=\"value?.getBlue().toString()\" (inputChange)=\"onInputChange($event, 'B')\" />\r\n @if (labelVisible()) {\r\n <span>B</span>\r\n }\r\n</div>\r\n@if (isAlphaVisible()) {\r\n <div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]+([\\.,][0-9]{1,2})?\" min=\"0\" max=\"1\" [value]=\"value?.getAlpha(true).toString()\" (inputChange)=\"onInputChange($event, 'A')\" />\r\n @if (labelVisible()) {\r\n <span>A</span>\r\n }\r\n </div>\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
|
|||
}] }); |
|||
|
|||
class HslaComponent { |
|||
@@ -1155,11 +1155,11 @@ class HslaComponent {
|
|||
this.color.set(newColor); |
|||
} |
|||
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: HslaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } |
|||
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: HslaComponent, isStandalone: true, selector: "hsla-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isAlphaVisible: { classPropertyName: "isAlphaVisible", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "<div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]*\" min=\"0\" max=\"360\" [value]=\"value?.getHue().toString()\" (inputChange)=\"onInputChange($event, 'H')\" />\r\n @if (labelVisible()) {\r\n <span>H</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]*\" min=\"0\" max=\"100\" [value]=\"value?.getSaturation() + '%'\" (inputChange)=\"onInputChange($event, 'S')\" />\r\n @if (labelVisible()) {\r\n <span>S</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]*\" min=\"0\" max=\"100\" [value]=\"value?.getLightness() + '%'\" (inputChange)=\"onInputChange($event, 'L')\" />\r\n @if (labelVisible()) {\r\n <span>L</span>\r\n }\r\n</div>\r\n@if (isAlphaVisible()) {\r\n <div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]+([\\.,][0-9]{1,2})?\" min=\"0\" max=\"1\" [value]=\"value?.getAlpha(true).toString()\" (inputChange)=\"onInputChange($event, 'A')\" />\r\n @if (labelVisible()) {\r\n <span>A</span>\r\n }\r\n </div>\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], dependencies: [{ kind: "directive", type: ColorPickerInputDirective, selector: "[inputChange]", inputs: ["min", "max"], outputs: ["inputChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|||
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: HslaComponent, isStandalone: true, selector: "hsla-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isAlphaVisible: { classPropertyName: "isAlphaVisible", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "<div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]*\" min=\"0\" max=\"360\" [value]=\"value?.getHue().toString()\" (inputChange)=\"onInputChange($event, 'H')\" />\r\n @if (labelVisible()) {\r\n <span>H</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]*\" min=\"0\" max=\"100\" [value]=\"value?.getSaturation() + '%'\" (inputChange)=\"onInputChange($event, 'S')\" />\r\n @if (labelVisible()) {\r\n <span>S</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]*\" min=\"0\" max=\"100\" [value]=\"value?.getLightness() + '%'\" (inputChange)=\"onInputChange($event, 'L')\" />\r\n @if (labelVisible()) {\r\n <span>L</span>\r\n }\r\n</div>\r\n@if (isAlphaVisible()) {\r\n <div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]+([\\.,][0-9]{1,2})?\" min=\"0\" max=\"1\" [value]=\"value?.getAlpha(true).toString()\" (inputChange)=\"onInputChange($event, 'A')\" />\r\n @if (labelVisible()) {\r\n <span>A</span>\r\n }\r\n </div>\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], dependencies: [{ kind: "directive", type: ColorPickerInputDirective, selector: "[inputChange]", inputs: ["min", "max"], outputs: ["inputChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|||
} |
|||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: HslaComponent, decorators: [{ |
|||
type: Component, |
|||
- args: [{ selector: `hsla-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ColorPickerInputDirective], template: "<div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]*\" min=\"0\" max=\"360\" [value]=\"value?.getHue().toString()\" (inputChange)=\"onInputChange($event, 'H')\" />\r\n @if (labelVisible()) {\r\n <span>H</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]*\" min=\"0\" max=\"100\" [value]=\"value?.getSaturation() + '%'\" (inputChange)=\"onInputChange($event, 'S')\" />\r\n @if (labelVisible()) {\r\n <span>S</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]*\" min=\"0\" max=\"100\" [value]=\"value?.getLightness() + '%'\" (inputChange)=\"onInputChange($event, 'L')\" />\r\n @if (labelVisible()) {\r\n <span>L</span>\r\n }\r\n</div>\r\n@if (isAlphaVisible()) {\r\n <div class=\"column\">\r\n <input type=\"text\" pattern=\"[0-9]+([\\.,][0-9]{1,2})?\" min=\"0\" max=\"1\" [value]=\"value?.getAlpha(true).toString()\" (inputChange)=\"onInputChange($event, 'A')\" />\r\n @if (labelVisible()) {\r\n <span>A</span>\r\n }\r\n </div>\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
|
|||
+ args: [{ selector: `hsla-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ColorPickerInputDirective], template: "<div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]*\" min=\"0\" max=\"360\" [value]=\"value?.getHue().toString()\" (inputChange)=\"onInputChange($event, 'H')\" />\r\n @if (labelVisible()) {\r\n <span>H</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]*\" min=\"0\" max=\"100\" [value]=\"value?.getSaturation() + '%'\" (inputChange)=\"onInputChange($event, 'S')\" />\r\n @if (labelVisible()) {\r\n <span>S</span>\r\n }\r\n</div>\r\n<div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]*\" min=\"0\" max=\"100\" [value]=\"value?.getLightness() + '%'\" (inputChange)=\"onInputChange($event, 'L')\" />\r\n @if (labelVisible()) {\r\n <span>L</span>\r\n }\r\n</div>\r\n@if (isAlphaVisible()) {\r\n <div class=\"column\">\r\n <input type=\"number\" pattern=\"[0-9]+([\\.,][0-9]{1,2})?\" min=\"0\" max=\"1\" [value]=\"value?.getAlpha(true).toString()\" (inputChange)=\"onInputChange($event, 'A')\" />\r\n @if (labelVisible()) {\r\n <span>A</span>\r\n }\r\n </div>\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
|
|||
}] }); |
|||
|
|||
class HexComponent { |
|||
@@ -1190,11 +1190,11 @@ class HexComponent {
|
|||
} |
|||
} |
|||
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: HexComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } |
|||
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: HexComponent, isStandalone: true, selector: "hex-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, prefixValue: { classPropertyName: "prefixValue", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "<div class=\"column\">\r\n <input #elRef type=\"text\" [value]=\"value\" (keyup)=\"onInputChange($event, elRef.value)\" />\r\n @if (labelVisible()) {\r\n <span>HEX</span>\r\n }\r\n</div>", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|||
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: HexComponent, isStandalone: true, selector: "hex-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, prefixValue: { classPropertyName: "prefixValue", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "<div class=\"column\">\r\n <input #elRef type=\"number\" [value]=\"value\" (keyup)=\"onInputChange($event, elRef.value)\" />\r\n @if (labelVisible()) {\r\n <span>HEX</span>\r\n }\r\n</div>", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|||
} |
|||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: HexComponent, decorators: [{ |
|||
type: Component, |
|||
- args: [{ selector: `hex-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "<div class=\"column\">\r\n <input #elRef type=\"text\" [value]=\"value\" (keyup)=\"onInputChange($event, elRef.value)\" />\r\n @if (labelVisible()) {\r\n <span>HEX</span>\r\n }\r\n</div>", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
|
|||
+ args: [{ selector: `hex-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "<div class=\"column\">\r\n <input #elRef type=\"number\" [value]=\"value\" (keyup)=\"onInputChange($event, elRef.value)\" />\r\n @if (labelVisible()) {\r\n <span>HEX</span>\r\n }\r\n</div>", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
|
|||
}] }); |
|||
|
|||
const OpacityAnimation = trigger('opacityAnimation', [ |
|||
rgbaToHsva(color) { |
|||
const red = color.red / 255; |
|||
|
|||
@ -0,0 +1,31 @@ |
|||
diff --git a/node_modules/ngx-hm-carousel/fesm2022/ngx-hm-carousel.mjs b/node_modules/ngx-hm-carousel/fesm2022/ngx-hm-carousel.mjs
|
|||
index 117f782..70e49a7 100644
|
|||
--- a/node_modules/ngx-hm-carousel/fesm2022/ngx-hm-carousel.mjs
|
|||
+++ b/node_modules/ngx-hm-carousel/fesm2022/ngx-hm-carousel.mjs
|
|||
@@ -1,5 +1,5 @@
|
|||
import * as i0 from '@angular/core'; |
|||
-import { Directive, inject, ViewContainerRef, TemplateRef, input, PLATFORM_ID, DestroyRef, Renderer2, NgZone, ChangeDetectorRef, viewChild, ElementRef, contentChildren, contentChild, computed, signal, effect, forwardRef, Component, ChangeDetectionStrategy } from '@angular/core';
|
|||
+import { Directive, inject, ViewContainerRef, TemplateRef, input, PLATFORM_ID, DestroyRef, Renderer2, NgZone, ChangeDetectorRef, viewChild, ElementRef, contentChildren, contentChild, computed, signal, effect, forwardRef, Component, ChangeDetectionStrategy, afterNextRender } from '@angular/core';
|
|||
import { DOCUMENT, isPlatformBrowser, NgTemplateOutlet, AsyncPipe } from '@angular/common'; |
|||
import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
|||
import { NG_VALUE_ACCESSOR } from '@angular/forms'; |
|||
@@ -340,7 +340,7 @@ class NgxHmCarouselComponent {
|
|||
}); |
|||
}); |
|||
}); |
|||
- const effectRef = effect(() => {
|
|||
+ afterNextRender(() => {
|
|||
this.rootElm = this.container().nativeElement; |
|||
this.containerElm = this.rootElm.children[0]; |
|||
this.init(); |
|||
@@ -365,10 +365,6 @@ class NgxHmCarouselComponent {
|
|||
]) |
|||
.pipe(takeUntilDestroyed(this._destroyRef)) |
|||
.subscribe(); |
|||
- // only exec once
|
|||
- effectRef.destroy();
|
|||
- }, {
|
|||
- allowSignalWrites: true,
|
|||
}); |
|||
} |
|||
ngOnDestroy() { |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue