What I am trying to do
I have a number of #extends that are build dynamically via a list in my SCSS project.
/// #type Map
$sizes-list: ( 'none', 'xs', 'sm', 'md', 'lg', 'xl' );
#each $size in $sizes-list {
/// #access public
%padding-#{$size} {
#include padding($size);
}
/// #access public
%padding-top-#{$size} {
#include padding-top($size);
}
/// #access public
%padding-right-#{$size} {
#include padding-top($size);
}
/// #access public
%padding-bottom-#{$size} {
#include padding-top($size);
}
/// #access public
%padding-left-#{$size} {
#include padding-top($size);
}
}
What I expected to happen
I thought I would generate 5 padding definitions generated for each iteration of the #each (30 definitions in total).
What actually happened
However I have noticed that these definitions that are rendered as part of a #each loop do not generate iteration of the loop when building the docs. What actually happen was only 5 definitions were documented without the $size value. I guess this is because the doc generator reads the file statically:
My questions
Is it possible to generate documentation for dynamically generated definitions like this? or,
Is there an alternative path I could take to document in this use case?
Related
I want to double click on any row to getting respective row values. It is an .Razor page.
First of all, I would create a component that will inherit from QuickGrid, so you can manage it easier in the future.
// CustomGrid.razor.cs
[CascadingTypeParameter( nameof(TGridItem) )]
public partial class CustomGrid<TGridItem> : QuickGrid<TGridItem>, IAsyncDisposable
{
[Inject]
private IJSRuntime JS { get; set; } // inject service in order to use JS interop
// sometimes it is mandatory to override base class parameters by your own
}
// CustomGrid.razor
#using Microsoft.AspNetCore.Components.QuickGrid // move it into the _Imports.razor
#typeparam TGridItem // QuickGrid is a generic-typed component
#inherits QuickGrid<TGridItem> // show inheritance
<div #ref="#_gridRef"> // HTML reference of current element
<QuickGrid TGridItem="TGridItem"
Items="#Items"
ItemsProvider="#ItemsProvider"
ChildContent="#ChildContent"
Class="#Class"
// more parameters... >
</QuickGrid>
</div>
Since there is no built-in functionality for adding your custom logic into QuickGrid, you will need to use some JavaScript interopability. Read about it more in docs here and here.
We need to declare some local variables in our CustomGrid.razor.cs:
private string? _rowValue; // specifies row value of currently double clicked row
private ElementReference _gridRef; // HTML element reference object that will be passed to JS function
private IJSObjectReference? _module; // JS module, a file that contains our JS functions
private DotNetObjectReference<CustomGrid<TGridItem>>? _objRef; // .NET object reference that will be passed to JS function in order to use its C# methods
And override some of the component lifecycle methods:
protected override void OnInitialized()
{
_objRef = DotNetObjectReference.Create( this ); // creates .NET object reference of current component instance
}
protected override async Task OnAfterRenderAsync( bool firstRender )
{
if( firstRender )
{
_module = await JS.InvokeAsync<IJSObjectReference>( "import", "./js/customGrid.js" ); // creates a reference of our JS module
if( _module is not null )
{
await _module.InvokeVoidAsync( "initialize", _gridRef, _objRef ); // calls our JS function and passes some arguments
}
}
}
Now, you need to create a JS module and a functions that will add desired logic for you on the first render of the CustomGrid component, like this:
// wwwroot/js/customGrid.js
export function initialize(customGrid, dotNetObj) {
if (customGrid) { // check if custom grid element exists
var rowValue;
const rows = customGrid.querySelectorAll('tbody > tr'); // get all rows except the header row
for (let i = 0; i < rows.length; i++) {
rows[i].addEventListener('dblclick', (e) => { // add event listener to current row in the loop
rowValue = e.path[1].innerText; // get innerText of current row in the loop
console.log(rowValue)
updateCurrentRowValue(rowValue, dotNetObj); // function that will return the current row value and refresh the UI
});
}
}
}
function updateCurrentRowValue(rowValue, dotNetObj) {
dotNetObj.invokeMethodAsync("UpdateCurrentRowValue", rowValue); // C# method
}
We're almost done here! If you would try to perform double click on the row, you would see an error in the console stating that CustomGrid does not contain a public method called UpdateCurrentRowValue. Let's add it like this:
[JSInvokable]
public void UpdateCurrentRowValue( string rowValue )
{
_rowValue = rowValue; // assign received rowValue from the JS function to our local _rowValue variable
StateHasChanged(); // force UI refresh
}
Now, all you need to do is to display your _rowValue:
// CustomGrid.razor
<div #ref="#_gridRef">
<QuickGrid TGridItem="TGridItem" . . . /> // collapsed for brevity
<p>Current Row Value: #_rowValue</p>
</div>
You will also need to Dispose your newly created objects of _module and _objRef using IAsyncDisposable.DisposeAsync method:
// CustomGrid.razor.cs
async ValueTask IAsyncDisposable.DisposeAsync()
{
if( _module is not null )
{
await _module.DisposeAsync();
}
_objRef?.Dispose();
}
Usage:
<CustomGrid Items="#people">
<PropertyColumn Property="#(p => p.PersonId)" Sortable="true" />
<PropertyColumn Property="#(p => p.Name)" Sortable="true" />
<PropertyColumn Property="#(p => p.BirthDate)" Format="yyyy-MM-dd" Sortable="true" />
</CustomGrid>
That should work. If you will need any help -- don't hesitate to ask!
Remarks:
This is a basic implementation of your request. It doesn't support scenarios when there are more than 1 grid on the page. It might work, but will be buggy, I guess. For that, you will need to add some more code in JS and CustomGrid code-behind. I didn't add it because it would be too much code in one answer (quite a lot of code came out here anyway).
UPD-1:
Removed custom [Parameter]s to override QuickGrid's ones and added a comment.
I want to merge class declarations in a .dt.s file to generate a cleaner public API. I am stuck on how to make this work with generic type arguments. Let's say I have:
class A1<T> { // Non-exported class I want to hide
data?: T;
}
export class B1 extends A1<string> {
}
Ideally, I want to turn this into:
export class B1 {
data?: string;
}
I can get the type of A1 and then copy its members. But how do get a resolved version of A1 that uses string instead of T?
For reference, this is my current code:
for (const heritageClause of node.heritageClauses) {
for (const type of heritageClause.types) {
if (isExported(type.modifiers)) {
exportedTypes.push(type);
} else {
const privateType = typeChecker.getTypeAtLocation(type);
if (privateType?.symbol?.members) {
privateType.symbol.members.forEach((definition, memberName) => {
if (!currentMembers || !currentMembers.has(memberName)) {
additionalMembers.push(...definition.declarations);
}
}
});
}
}
}
I believe the method you are looking for is TypeChecker#getTypeOfSymbolAtLocation(symbol, node).
The following should get the resolved type of string | undefined:
// by the way, recommend renaming `type` to `typeNode` to avoid confusion
typeChecker.getTypeOfSymbolAtLocation(privateType.getProperties()[0], type);
i want to create an abstract class with abstract functions in QML in theory some thing like this:
//abstract.qml
QtObject{
abstract function implementLater(var input);
}
Abstract{
//and here i have to implement it
function implementLater(var input){
console.log(input)
}
}
how can i do this in qml or maybe in c++ and register it to qml?
update :
here is what i'm trying to do, in my uvaluemask object i should have a function named mask which will be abstract and i call this for every child which will be different, you can call childs method directly i'm doing this right now and its working, but my component "UValueMask" is missing difinition for mask method,i mean i need to force users of UValueMask to define a mask method .
//UValueMask.qml
QtObject {
property string name:""
}
//singleton Object
UListObject{
property UValueMask timeMask :UValueMask{
id:timemask
name: "time"
function mask(input,splitter){
return innerObj.convertIntToTime(input,splitter)
}
}
property UValueMask dateMask: UValueMask{
id:datemask
name:"date"
function mask(input,splitter){
return innerObj.convertIntToDate(input,splitter)
}
}
}
I want to check if the value provides to a function is a map or not.
#function func($props...) {
#if(is-map($props)) {
#return 'something';
}
#else {}
}
h1 {
color: func((color: red));
}
I'm getting the error:
(color: red) isn't a valid CSS value.
What am I doing wrong?
I personally never heard about any native Sass function called is-map. If you want to check the type of something, use the type-of function, so for example, checking for type-of($props) == map would solve your problem in this case.
#function func($props...) {
#if(type-of($props) == map) {
#return 'something';
}
#else {}
}
Because function returns map. Not a color as expected. Use map-get to get the access to properties values.
#return map-get($props, color);
And you have the variable argument. To get the first of arguments use nth($props, 1).
Sassmeister demo.
Update
If parameters in map are dynamic you can use this mixin instead of function.
#mixin print($declarations) {
#if $declarations {
#each $property, $value in $declarations {
#{$property}: $value
}
} #else {
#error "mixin print: $declarations is not specified";
}
}
Mixin sassmeister demo.
Is there any way to pass a function or a mixin by reference to another function or mixin in SASS, and then call the referenced function or mixin?
For example:
#function foo($value) {
#return $value;
}
#mixin bob($fn: null) {
a {
b: $fn(c); // is there a way to call a referenced function here?
}
}
#include bob(foo); // is there any way I can pass the function "foo" here?
Functions and mixins are not first-class in Sass, meaning you can't pass them around as arguments like you can with variables.
Sass 3.2 and older
The closest you can get is with the #content directive (Sass 3.2+).
#mixin foo {
a {
#content;
}
}
#include bob {
b: foo(c); // this replaces `#content` in the foo mixin
}
The only caveat is that the #content can't see what's inside your mixin. In other words, if c was only defined inside the bob mixin, it essentially wouldn't exist because it isn't considered in scope.
Sass 3.3 and newer
Starting with 3.3, you can use the call() function, but it is only for use with functions, not mixins. This requires passing string containing the name of the function as the first argument.
#function foo($value) {
#return $value;
}
#mixin bob($fn: null) {
a {
b: call($fn, c);
}
}
#include bob('foo');